feat: translate Stellar tx failure codes into plain-English explanations#522
Merged
Tinna23 merged 7 commits intoJun 21, 2026
Merged
Conversation
Description: Closes StellarCommons#510 Add explain/failure.rs with translators for all 9 tx-level and 7 op-level Horizon result codes, with graceful fallback for unknown codes Add ResultCodes to models/transaction.rs; extend Transaction to carry raw result codes from Horizon Parse extras.result_codes and top-level result_codes in services/horizon.rs Wire codes through services/explain.rs into TransactionExplanation.failure_reason and operation_failures 34 new unit tests; all 198 tests pass
…cargo fmt to fix line-length wrapping in failure.rs and transaction.rs - Collapse nested if-let in transaction_cache.rs to satisfy clippy::collapsible_if - Run cargo fmt to fix line-length wrapping in failure.rs and transaction.rs - Collapse nested if-let in transaction_cache.rs to satisfy clippy::collapsible_if The 3 files to stage before committing: packages/core/src/explain/failure.rs packages/core/src/explain/transaction.rs packages/core/src/services/transaction_cache.rs
fromW, toW, and amtW were computed but never referenced in the output, causing @typescript-eslint/no-unused-vars lint errors that blocked CI. File to stage: packages/cli/src/formatters/transaction.ts
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description: Closes #510
feat: translate Stellar transaction failure codes into plain-English explanations
Closes #510
Summary
When a Stellar transaction fails, Horizon returns structured error codes (
tx_bad_seq,op_no_trust, etc.) that are meaningless to end users. This PR parses those codes and adds two new fields to the transaction explanation response:failure_reason— a plain-English sentence explaining why the transaction failed and what the user can do about itoperation_failures[]— per-operation breakdown with the original code, its index, and a human-readable explanationSuccessful transactions return
failure_reason: nullandoperation_failures: [].Example response (before → after)
Before
{ "successful": false, "summary": "This failed transaction contains 1 payment." }After
{ "successful": false, "summary": "This failed transaction contains 1 payment.", "failure_reason": "Transaction failed: Sequence number is out of date — another transaction from this account may have been submitted first. Try again.", "operation_failures": [ { "index": 0, "code": "op_no_trust", "explanation": "The destination account has not opted in to hold this asset." } ] }Error codes covered
Transaction-level (
result_codes.transaction)tx_bad_seqtx_bad_authtx_insufficient_balancetx_no_accounttx_insufficient_feetx_too_earlytx_too_latetx_missing_operationtx_bad_auth_extraOperation-level (
result_codes.operations[])op_no_trustop_underfundedop_no_destinationop_not_authorizedop_line_fullop_no_issuerop_low_reserveop_successentries are silently excluded fromoperation_failures[].Files changed
packages/core/src/explain/failure.rsOperationFailurestruct,translate_tx_code,translate_op_code,explain_failurepackages/core/src/explain/mod.rspub mod failurepackages/core/src/models/transaction.rsResultCodesstruct; addresult_codes: Option<ResultCodes>field toTransactionpackages/core/src/services/horizon.rsHorizonResultCodes+HorizonExtrasstructs; extendHorizonTransactionto deserialize bothextras.result_codes(submission error shape) and top-levelresult_codes(fetch-by-hash shape)packages/core/src/services/explain.rsmap_transaction_to_domainnow extracts result codes from whichever Horizon shape is presentpackages/core/src/explain/transaction.rsfailure_reason+operation_failurestoTransactionExplanation; wireexplain_failure()intoexplain_transaction_with_ledgerAcceptance criteria
failure_reasonwith a plain-English explanationoperation_failures[]array present when operations also have error codesfailure_reason: nullandoperation_failures: []cargo testpasses with no regressionsTest evidence
cargo test— 198 passed, 0 failedTotal: 213 tests executed — 198 unit + 15 doc-tests — 0 failures