A common mistake in Rust projects is mixing application and library error styles. I use thiserror for typed library errors and anyhow for top-level binaries.

Libraries expose specific variants so callers can branch by cause. Binaries add context and preserve chains for diagnostics.

When errors cross async boundaries, structured context messages become essential. I include identifiers like device ID and operation name in every wrapped error.

This pattern keeps API surfaces precise while still making CLI and service logs readable during incidents.