Skip to content

transaction: failure outcomes name the entry by processing-order index, not the client's Bundle index #922

Description

@aacruzgon

Summary

When a transaction Bundle fails at an entry, the OperationOutcome names the entry by its index in the server's processing order (DELETE → POST → PUT/PATCH → GET), not the index in the Bundle the client sent.

Current behavior

process_transaction in the REST layer sorts the entries by method_processing_order before handing them to the backend. The backend reports a failure as TransactionError::BundleError { index, .. } using its position in that sorted list, and transaction_error_response_parts renders it verbatim as "Transaction failed at entry {index}: …".

Reproduced on the batch_conformance harness with two seeded Patients matching identifier=http://example.org|12345:

entry 0: PUT  Patient/x                                        (valid)
entry 1: POST Patient, ifNoneExist=identifier=http://example.org|12345   (ambiguous → 412)

400 Bad Request
"Transaction failed at entry 0: Entry failed with status 412"

The failing entry is the client's entry 1; POST sorts before PUT, so the backend saw it at index 0. The overlap message added by #919 (… which entry {other} … also addresses) names both entries by the same sorted index.

Expected behavior

The index in the message refers to the entry's position in the request Bundle, since that is the only numbering the client can act on.

Evidence

  • crates/rest/src/handlers/batch.rs:628indexed_entries.sort_by_key(|(_, entry, _)| method_processing_order(&entry.method)); each element still carries its original index as the first tuple field
  • crates/rest/src/handlers/batch.rs:2421transaction_error_response_parts formats BundleError { index } unmapped
  • crates/persistence/src/core/bundle_conditionals.rs:120check_identity_overlap names two entries by executor index

Suggested approach

The mapping already exists in process_transaction: indexed_entries[index].0 is the original index. Map BundleError.index through it before rendering, in the Err arm that calls transaction_error_response_parts, and do the same for the audit fan-out's entry_index if it reads the sorted position. For the overlap message, either have the REST layer rewrite both indices (they are embedded in text, so a structured variant such as BundleError { index, related: Option<usize> } or a dedicated TransactionError::OverlappingIdentity { index, other } would be cleaner) or pass the original indices down on BundleEntry so the executors report them directly. The structured variant also gives the 400 a better issue code than processing.

Test: batch_conformance — the reproduction above, asserting the message names entry 1; and an overlap case whose conditional entry precedes the instance entry in the request but follows it after sorting.

Found while implementing #859 (PR #919).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions