Skip to content

Resolve contract error names from WASM spec during invocation#2377

Open
BlaineHeffron wants to merge 9 commits intostellar:mainfrom
BlaineHeffron:feature/contract-error-text-in-invocation
Open

Resolve contract error names from WASM spec during invocation#2377
BlaineHeffron wants to merge 9 commits intostellar:mainfrom
BlaineHeffron:feature/contract-error-text-in-invocation

Conversation

@BlaineHeffron
Copy link
Contributor

What

When a contract invocation fails, resolve the numeric error code (e.g. Error(Contract, #1)) to its human-readable name and documentation string from the contract's WASM spec, and display it directly next to the error code in the CLI output.

Before:
❌ error: transaction simulation failed: HostError: Error(Contract, #1)

Event log (newest first):
0: [Diagnostic Event] ...

After:
❌ error: transaction simulation failed: HostError: Error(Contract, #1)
NotFound: The requested resource was not found.

Event log (newest first):
0: [Diagnostic Event] ...

Why

Contract authors define error enums with meaningful names and documentation in their Soroban contracts (e.g. NotFound = 1 with doc "The requested resource was not found."), but the CLI only showed the raw numeric code #1. This made debugging contract failures unnecessarily difficult — users had to manually cross-reference error codes against the contract source. The WASM spec already contains this information; the CLI just wasn't using it.

This change handles all three error paths in contract invocation (first simulation, second simulation, and transaction submission), parses error codes from both the Display format (Error(Contract, #N)) and Debug format (Contract(N)), and searches all error enums in the spec rather than only the one named "Error" to support contracts with multiple error enums from dependencies.

Known limitations

  • Error code extraction relies on string pattern matching against the RPC error message format (Contract, #N and Contract(N)). If the upstream error format changes, the parsing would need to be updated.
  • The resolved error name is inserted before the event log by splitting at the first blank line (\n\n) in the error string. If the RPC response format changes to not include a blank line separator, the resolved name would fall back to appearing at the end of the message.
  • Non-contract Soroban errors (Budget, Auth, etc.) are intentionally not resolved — only ScError::Contract(u32) codes are matched.

@github-project-automation github-project-automation bot moved this to Backlog (Not Ready) in DevX Jan 29, 2026
@BlaineHeffron BlaineHeffron marked this pull request as ready for review January 29, 2026 23:21
Copilot AI review requested due to automatic review settings January 29, 2026 23:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enhances contract invoke error reporting by resolving ScError::Contract(u32) numeric codes into human-readable error names/docs from the contract WASM spec and inserting that detail into the CLI error output.

Changes:

  • Map RPC failures during simulation/submission through an error “enhancer” that extracts contract error codes and injects resolved name/doc into the message.
  • Add Spec::find_error_type_any to locate an error case by numeric value across all error enums in the spec.
  • Update/extend tests to assert the new enriched error output behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
cmd/soroban-cli/src/commands/contract/invoke.rs Adds contract error-code extraction and error-message enhancement using the contract spec; adjusts error display formatting; adds unit tests for parsing.
cmd/crates/soroban-test/tests/it/integration/custom_types.rs Updates integration test expectations to validate enriched error output and the returned detail string.
cmd/crates/soroban-spec-tools/src/lib.rs Adds find_error_type_any to search all error enums for a matching numeric error code.

Copy link
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏🏻 Very cool idea.

@BlaineHeffron
Copy link
Contributor Author

I switched to using the simulation transaction result to obtain the error code. This is done by parsing the events in reverse order (latest first). We also make sure to only match codes if the function has a declared error enum. If it doesn't, the old behavior remains. Finally, we distinguish error codes from cross-contract call failures with codes from the invoked contract. This is done by checking the event data for "escalating error to VM trap from failed host function call: call"

This string check appears to be required to catch the non-mapped cross contract error case. Without it we would mislabel a cross contract error with the invoked function's error description if their codes collided. Since this string check would break if the rpc protocol changed the string used, I added several integration tests that would catch potential regressions.

Note:

Both panic_with_error! and non-try cross-contract calls produce VM traps, but with different host function names:

  • panic_with_error!: "escalating error to VM trap from failed host function call: fail_with_error"
  • cross-contract trap: "escalating error to VM trap from failed host function call: call"
    We do want to map panic_with_error!, so we have to check the full "call: call" portion of the string.

New Integration Tests (8 total)

Added error_caller contract with functions demonstrating all cross-contract patterns:

  • catch_call / catch_call_same_code / catch_call_import - try-call with error remapping
  • call / call_import - non-try calls that trap
  • catch_panic_no_result - try-call but returns u32 not Result

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

Labels

None yet

Projects

Status: Backlog (Not Ready)

Development

Successfully merging this pull request may close these issues.

2 participants