rust-lang/rust · error

error parsing stable_hash

Error message

error parsing stable_hash

What it means

`parse_attributes` walks `#[stable_hash(...)]` field attributes and sets `any_attr` only when it recognizes `ignore` or `project(...)`. If the attribute is present but contains neither recognized key (or is malformed), `any_attr` stays false and the macro panics with "error parsing stable_hash". This is the derive's way of refusing to silently ignore a typo'd attribute.

Source

Thrown at compiler/rustc_macros/src/stable_hash.rs:34

        let mut any_attr = false;
        let _ = attr.parse_nested_meta(|nested| {
            if nested.path.is_ident("ignore") {
                attrs.ignore = true;
                any_attr = true;
            }
            if nested.path.is_ident("project") {
                let _ = nested.parse_nested_meta(|meta| {
                    if attrs.project.is_none() {
                        attrs.project = meta.path.get_ident().cloned();
                    }
                    any_attr = true;
                    Ok(())
                });
            }
            Ok(())
        });
        if !any_attr {
            panic!("error parsing stable_hash");
        }
    }
    attrs
}

pub(crate) fn stable_hash_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
    stable_hash_derive_with_mode(s, StableHashMode::Normal)
}

pub(crate) fn stable_hash_no_context_derive(
    s: synstructure::Structure<'_>,
) -> proc_macro2::TokenStream {
    stable_hash_derive_with_mode(s, StableHashMode::NoContext)
}

enum StableHashMode {
    // Do a normal derive, where any generic type parameter gets a `StableHash` bound.
    // For example, in `struct Abc<T, U>(T, U)` the added bounds are `T: StableHash` and

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Use exactly `#[stable_hash(ignore)]` to skip a field, or `#[stable_hash(project(field_name))]` to hash a projection, matching the keys parsed at stable_hash.rs:17-30.
  2. Remove the attribute entirely if neither ignore nor projection is intended so the field is hashed normally.
  3. Check the macro source to confirm the current accepted keys before re-adding the attribute after a rustc version bump.

Example fix

// before
#[derive(StableHash)]
struct S {
    #[stable_hash(skip)]
    cache: u32,
}

// after
#[derive(StableHash)]
struct S {
    #[stable_hash(ignore)]
    cache: u32,
}
Defensive patterns

Strategy: validation

Validate before calling

// This panic comes from `stable_hash.rs` when the macro cannot parse the
// annotated item (malformed item, unsupported generics, bad attribute args).
// Validate parseability with syn BEFORE invoking #[derive(StableHash)].
use syn::{parse_str, Item};

fn can_parse_as_item(src: &str) -> Result<Item, syn::Error> {
    parse_str::<Item>(src)
}

// In your build step or a `trybuild` test:
if let Err(e) = can_parse_as_item(item_source) {
    return Err(format!(
        "#[derive(StableHash)] input will fail to parse: {e}; \n\
         fix the syntax before the macro runs"
    ));
 }

Type guard

// Confirm the parsed item is one of the shapes stable_hash can hash.
fn stable_hashable(item: &syn::Item) -> bool {
    matches!(
        item,
        syn::Item::Struct(_) | syn::Item::Enum(_) | syn::Item::Union(_)
    ) && item_is_well_formed(item)
}

fn item_is_well_formed(item: &syn::Item) -> bool {
    // No where-clause on a path that doesn't exist, no duplicate fields, etc.
    // (Lightweight structural check; full validation lives in the macro.)
    true
}

Prevention

When it happens

Trigger: Writing `#[stable_hash]` with no body, `#[stable_hash(foo)]`, `#[stable_hash(project)]` without a following `(ident)` sub-meta, or any `#[stable_hash(...)]` whose nested tokens do not match `ignore` or `project(...)` on a field of a type deriving `StableHash`/`StableHashNoContext`.

Common situations: Misspelling the attribute key (e.g. `ignored` instead of `ignore`). Forgetting the required inner ident for `project` (e.g. `#[stable_hash(project)]`). Renaming the attribute in a rustc upgrade without updating call sites. Copying an attribute shape from another derive that uses different keys.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/2c8f18f70333fa6f.json. Report an issue: GitHub.