Skip to content

Introduce consistent typed error handling#85

Open
protocolwhisper wants to merge 1 commit into
zk-kit:mainfrom
protocolwhisper:main
Open

Introduce consistent typed error handling#85
protocolwhisper wants to merge 1 commit into
zk-kit:mainfrom
protocolwhisper:main

Conversation

@protocolwhisper
Copy link
Copy Markdown

Description

This PR improves error handling across the IMT and SMT libraries by replacing ad-hoc or manually managed errors with explicit custom error types.

What kind of change does this PR introduce?

Refactor / API improvement

What is the current behavior?

In imt, several public methods returned Result<_, &'static str>, for example:

  • new
  • insert
  • update
  • delete
  • create_proof

These methods returned plain string errors such as "The tree is full" or "The leaf does not exist in this tree" instead of structured error values. In smt, there was already an SMTError enum, but its Display and std::error::Error implementations were handwritten inside smt.rs.

What is the new behavior?

This PR introduces dedicated error modules and typed error enums:

  • ImtError in crates/imt/src/errors.rs
  • SMTError in crates/smt/src/errors.rs

For imt, methods now return Result<_, ImtError> instead of Result<_, &'static str>, with concrete variants such as:

  • TooManyLeaves { got, arity, depth, max }
  • TreeFull
  • NotContained

For smt, the existing error handling is cleaned up by moving SMTError into its own module and deriving thiserror::Error, replacing the manual Display and Error implementations. The InvalidParameterType variant is also changed to a named-field variant for clearer context.

Why the previous version was problematic

Returning Err("...") from public APIs is less robust than using a dedicated error type. As described in Rust By Example: Defining an error type, custom error types are preferable when a function may fail in different ways, because they make failures explicit, easier to match on, and easier to extend with contextual information.

That applies directly here:

  • a plain &'static str does not let callers reliably pattern-match on error variants,
  • it cannot carry structured fields like got, max, arity, and depth,
  • and it makes library APIs more brittle because callers may end up depending on message text instead of error semantics.

Does this PR introduce a breaking change?

Yes.

This changes public return types in imt from Result<_, &'static str> to Result<_, ImtError>. Users who were matching on string errors or expecting &'static str will need to update their code to handle ImtError instead. The SMT refactor may also affect users importing or referencing SMTError from its previous location.

Other information

This change makes the libraries more idiomatic and easier to maintain by using typed errors with thiserror, and by separating error definitions into dedicated modules. It also improves debuggability by attaching structured information to certain failures instead of only returning fixed strings.

Checklist

  • I have read and understand the contributor guidelines and code of conduct.
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings

Comment thread crates/imt/src/errors.rs
Comment thread crates/imt/src/errors.rs Outdated
Comment thread crates/smt/src/errors.rs Outdated
Comment thread crates/smt/src/errors.rs
Comment thread crates/imt/src/errors.rs Outdated
Comment thread crates/smt/src/errors.rs Outdated
Comment thread crates/imt/Cargo.toml Outdated
Comment thread crates/smt/Cargo.toml Outdated
Comment thread crates/smt/src/smt.rs
Comment thread crates/imt/src/imt.rs
) -> Result<IMT, &'static str> {
if leaves.len() > arity.pow(depth as u32) {
return Err("The tree cannot contain more than arity^depth leaves");
) -> Result<IMT, ImtError> {
Copy link
Copy Markdown
Contributor

@0x471 0x471 Mar 23, 2026

Choose a reason for hiding this comment

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

This is a breaking change since SMTError import path changes and InvalidParameterType variant shape change from tuple to named fields.

How should we approach this? @vplasencia

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

For this what about we use #[deprecated(note = "Use new_with_error instead")] ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it doesn't apply here since you can't deprecate a variant shape change, and there's no new_with_error method?

Let's confirm with Vivian how to approach these kind of breaking changes

Comment thread crates/smt/src/errors.rs Outdated
Comment thread crates/imt/src/lib.rs
Comment thread crates/smt/src/lib.rs
@0x471
Copy link
Copy Markdown
Contributor

0x471 commented Mar 23, 2026

Besides the comments, there are a few minor issues related to the contribution guidelines:

  • rebase is not a valid commit type
  • the type should not be wrapped in parentheses
  • the subject should not be capitalized

Could you please squash these commits into something like:
refactor(imt,smt): introduce typed error handling with thiserror? @protocolwhisper

@protocolwhisper
Copy link
Copy Markdown
Author

Thanks for the comments @0x471, it's more ergonomic now and I just squash all the changes in one commit

Comment thread crates/imt/src/errors.rs

#[derive(Error, Debug, PartialEq, Eq)]
pub enum ImtError {
#[error("Too many leaves: got {got}, max for arity {arity} and depth {depth} is max {max}")]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not a blocker but there's a redundant "max" word here

@0x471
Copy link
Copy Markdown
Contributor

0x471 commented Mar 25, 2026

Thanks for the PR, @protocolwhisper! Let’s sync with Vivian on how to handle the SMTError breaking change, and aside from that, this looks good to me to merge

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.

2 participants