Skip to content

Fix Result type generation for user-defined error enums named "Error"#1709

Open
willemneal wants to merge 2 commits intostellar:mainfrom
theahaco:fix/error_generation
Open

Fix Result type generation for user-defined error enums named "Error"#1709
willemneal wants to merge 2 commits intostellar:mainfrom
theahaco:fix/error_generation

Conversation

@willemneal
Copy link
Copy Markdown
Contributor

@willemneal willemneal commented Jan 29, 2026

Fix Result type generation for user-defined error enums named "Error"

What

Remove the special case in map_type that mapped the type name "Error" to
ScSpecTypeDef::Error. User-defined error enums are now always treated as
UDTs (user-defined types), regardless of their name.

Why

When a contract defined an error enum named Error and used it in a
Result<T, Error> return type, the generated client code incorrectly
produced Result<T, soroban_sdk::Error> instead of Result<T, Error>.

This happened because map_type.rs had a special case that mapped any type
named "Error" to ScSpecTypeDef::Error (the built-in error type), even when
it was a user-defined error enum. Error enums with other names like MyError
worked correctly because they fell through to the UDT handling.

The fix removes this special case so that all user-defined types, including
those named "Error", are treated as UDTs and generate correct client code.

Example - before the fix:

// Contract defines:
pub enum Error { Overflow = 1 }
pub fn safe_add(a: u64, b: u64) -> Result<u64, Error>

// Generated client had:
fn try_safe_add(...) -> Result<..., Result<soroban_sdk::Error, ...>>

Example - after the fix:

// Generated client now correctly has:
fn try_safe_add(...) -> Result<..., Result<Error, ...>>

Close #1710

Known limitations

N/A

Co-Authored-By: Claude Opus 4.5 noreply@anthropic.com

Copilot AI review requested due to automatic review settings January 29, 2026 18:13
Copy link
Copy Markdown
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

This PR fixes an issue where user-defined error enums named "Error" were incorrectly mapped to the built-in soroban_sdk::Error type instead of being treated as user-defined types (UDTs). The fix ensures that all error enums in contract return types are properly represented as UDTs in the contract specification.

Changes:

  • Removed special-case handling of "Error" as a built-in type in type mapping
  • Added comprehensive test coverage for Result types with user-defined error enums
  • Verified the fix works for both "Error" and "MyError" custom error types

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
soroban-sdk-macros/src/map_type.rs Removed line that mapped "Error" to built-in error type; added unit tests verifying "Error" and "MyError" map to UDTs
tests/add_u64/src/lib.rs Added two error enums and safe_add functions to test Result type generation
tests/import_contract/src/lib.rs Added Error enum and functions that use imported contract's error types
tests/add_u64/test_snapshots/test/test_safe_add.1.json Added ledger snapshot for new test case
soroban-spec-rust/src/lib.rs Added integration tests verifying correct Result type generation for user-defined errors

@willemneal
Copy link
Copy Markdown
Contributor Author

I used this as a test for Claude at finding and fixing the bug I found. I provided the minimal example and it found and fixed it very quickly. And now it being reviewed by another AI which had no comments feels like a new era.

@leighmcculloch My only question is whether there would ever be the case that the Error type in ScTypeDef would be found in a contract spec. Is it supposed to map to soroban_sdk::Error?

@leighmcculloch
Copy link
Copy Markdown
Member

Can you open an issue to go into detail about the problem to make sure we fully capture this bug, it's scope of impact, before we focus on the solution?

We can do some analysis of contracts on mainnet to understand how changing the existing behaviour might break existing contracts, or if there's any impact today that we might need to think differently about.

I suspect this fix is right though when we come back to it.

Side note, this might be resolved by planned work around improving type identities (#1570).

@leighmcculloch
Copy link
Copy Markdown
Member

My only question is whether there would ever be the case that the Error type in ScTypeDef would be found in a contract spec. Is it supposed to map to soroban_sdk::Error?

Yes I think so. Error is an SDK type, it's a valid type to appear at a contract boundary. Whether it is frequently used is a good question though, it may not be.

@leighmcculloch
Copy link
Copy Markdown
Member

Although the Error type captures a much larger range of errors than what a contract fn could return, so there's an argument for not supporting it, or finding some other way to capture that use case. 🤔

@leighmcculloch
Copy link
Copy Markdown
Member

willemneal and others added 2 commits April 15, 2026 11:38
Remove the special case in `map_type` that mapped the type name "Error" to
`ScSpecTypeDef::Error`. User-defined error enums are now always treated as
UDTs (user-defined types), regardless of their name.

When a contract defined an error enum named `Error` and used it in a
`Result<T, Error>` return type, the generated client code incorrectly
produced `Result<T, soroban_sdk::Error>` instead of `Result<T, Error>`.

This happened because `map_type.rs` had a special case that mapped any type
named "Error" to `ScSpecTypeDef::Error` (the built-in error type), even when
it was a user-defined error enum. Error enums with other names like `MyError`
worked correctly because they fell through to the UDT handling.

The fix removes this special case so that all user-defined types, including
those named "Error", are treated as UDTs and generate correct client code.

Example - before the fix:
```rust
// Contract defines:
pub enum Error { Overflow = 1 }
pub fn safe_add(a: u64, b: u64) -> Result<u64, Error>

// Generated client had:
fn try_safe_add(...) -> Result<..., Result<soroban_sdk::Error, ...>>
```

Example - after the fix:
```rust
// Generated client now correctly has:
fn try_safe_add(...) -> Result<..., Result<Error, ...>>
```

N/A

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@willemneal willemneal force-pushed the fix/error_generation branch from b5bc732 to db61291 Compare April 15, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generated client code uses wrong Error type when user-defined error enum is named "Error"

3 participants