biomejs/biome · error · syn::Error
Unexpected attribute: {meta_text}
Error message
Unexpected attribute: {meta_text} What it means
Compile-time error from the #[deserializable] derive of biome_deserialize_macros (struct_field_attrs.rs:97). Inside the deprecated(...) attribute on a struct field, every nested item must be a name-value pair with a string literal (message = "..." or use_instead = "..."). Any other shape - a bare word like deprecated(note), a nested list, or a non-string literal like deprecated(message = 5) - fails the Meta::NameValue-with-Lit::Str pattern match and produces this 'Unexpected attribute' error at the offending token span.
Source
Thrown at crates/biome_deserialize_macros/src/deserializable_derive/struct_field_attrs.rs:97
..
}) => {
if path.is_ident("rename") {
opts.rename = Some(s.value())
} else if path.is_ident("validate") {
opts.validate = Some(s.parse()?)
}
}
Meta::List(_) if meta.path().is_ident("deprecated") => {
let mut deprecated = None;
parse_meta_list(meta, |meta| {
let Meta::NameValue(MetaNameValue {
path,
lit: Lit::Str(s),
..
}) = meta
else {
let meta_text = meta.to_token_stream().to_string();
return Err(Error::new(
meta.span(),
format_args!("Unexpected attribute: {meta_text}"),
));
};
deprecated = if deprecated.is_some() {
return Err(Error::new(
meta.span(),
"Only one attribute expected inside deprecated()",
));
} else if path.is_ident("message") {
Some(DeprecatedField::Message(s.value()))
} else if path.is_ident("use_instead") {
Some(DeprecatedField::UseInstead(s.value()))
} else {
let path_text = path.to_token_stream().to_string();
return Err(Error::new(
path.span(),
format_args!(View on GitHub (pinned to 405dedb0ff)
Solutions
- Use the two supported keys with string literals: #[deserializable(deprecated(message = "Use `otherField` instead."))] or deprecated(use_instead = "OtherField")
- If you wanted version metadata like since = "1.2", drop it - only message and use_instead are supported inside deprecated()
- Run cargo check on the crate after editing attributes; the error points at the exact nested token span
Example fix
// before #[deserializable(deprecated(since = "1.2"))] pub old_option: bool, // after #[deserializable(deprecated(use_instead = "NewOption"))] pub old_option: bool,
Defensive patterns
Strategy: validation
Validate before calling
// Rust - only these two shapes are valid inside deprecated() #[deserializable(deprecated(message = "Use `new_field` instead."))] pub old_field: bool, #[deserializable(deprecated(use_instead = "NewField"))] pub other: bool,
Prevention
- Inside deprecated(...) always write key = "string literal"; never bare words or non-string literals
- Keep a compiling reference field with deprecated(...) in the crate to copy syntax from
- Run cargo check immediately after editing derive attributes so the span points at the bad token
When it happens
Trigger: Writing #[deserializable(deprecated(anything))] (bare path), #[deserializable(deprecated(message = 5))] (integer literal), or #[deserializable(deprecated("use bar"))] (string literal instead of name-value) on a field of a type deriving Deserializable.
Common situations: Adding deprecation metadata to configuration option structs in biome_configuration or downstream crates using biome_deserialize; copy-pasting serde-style syntax (since = "1.2", note = "...") which this macro does not support inside deprecated().
Related errors
- Only one attribute expected inside deprecated()
- Unexpected attribute inside deprecated(): {path_text}
- A list of attribute is expected
- token kind {kind:?} cannot be transformed to text
- formatting embedded JavaScript snippets requires the `js_emb
AI-assisted analysis of biomejs/biome@405dedb0ff (2026-08-20).
Data as JSON: /api/errors/757af445abd27f80.
Report an issue: GitHub.