Hash handling-rust-errors
HASH error handling patterns using error-stack crate. Use when working with Result types, Report types, defining custom errors, propagating errors with change_context, adding context with attach, implementing Error trait, or documenting error conditions in Rust code.
install
source · Clone the upstream repo
git clone https://github.com/hashintel/hash
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/hashintel/hash "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/handling-rust-errors" ~/.claude/skills/hashintel-hash-handling-rust-errors && rm -rf "$T"
manifest:
.claude/skills/handling-rust-errors/SKILL.mdsource content
Rust Error-Stack Patterns
HASH-specific error handling patterns using the
error-stack crate for consistent, debuggable error handling across the Rust codebase.
Core Principles
HASH uses
exclusively for error handling:error-stack
✅ DO:
- Use
for all error typesReport<MyError> - Use concrete error types:
Report<MyError> - Import
fromError
(notcore::error::
)std::error:: - Import
for trait methodsResultExt as _
❌ DON'T:
- Use
oranyhow
crateseyre - Use
(except in tests/prototyping)Box<dyn Error> - Use
Report<Box<dyn Error>> - Use
(usethiserror
instead)derive_more
HashQL Compiler Exception
HashQL compiler code uses a different error handling approach.
Code in
libs/@local/hashql/* uses the hashql-diagnostics crate instead of error-stack. This is because compiler errors require rich formatting capabilities:
- Source spans pointing to exact code locations
- Multiple labeled regions within the same diagnostic
- Fix suggestions with replacement text
- Severity levels (error, warning, hint)
Which approach to use:
| Location | Error Handling |
|---|---|
(compiler code) | Use → See writing-hashql-diagnostics skill |
| Everywhere else | Use patterns from this skill |
Traditional
error-stack patterns still apply for HashQL infrastructure code (CLI, file I/O, configuration) that doesn't involve compiler diagnostics.
Quick Start Guide
Choose the reference that matches your current task:
Defining Errors
Use when: Creating new error types or error enums
- Define error types with
derive_more - Error enum patterns and variants
- Implement the
traitError - Error type hierarchies
Propagating Errors
Use when: Handling
Result types, using ? operator
- Convert errors with
and.change_context().change_context_with() - Add context with
and.attach().attach_with() - Error conversion patterns
Documenting Errors
Use when: Writing doc comments for fallible functions
section format# Errors- Link error variants
- Document runtime errors
- Test error conditions
Common Quick Patterns
Creating an Error
use error_stack::Report; return Err(Report::new(MyError::NotFound)) .attach(format!("ID: {}", id));
Propagating with Context
use error_stack::ResultExt as _; some_result .change_context(MyError::OperationFailed) .attach("Additional context")?;
Lazy Context (for expensive operations)
use error_stack::ResultExt as _; expensive_operation() .change_context(MyError::OperationFailed) .attach_with(|| format!("Debug info: {:?}", expensive_computation()))?;
References
- Defining Errors - Creating new error types or error enums
- Propagating Errors - Handling
types, usingResult
operator? - Documenting Errors - Writing doc comments for fallible functions