denoland/deno · error · syn::Error
Unknown attribute `{attr_name}`
Error message
Unknown attribute `{attr_name}` What it means
This is the catch-all of op2's attribute classifier (libs/ops/op2/signature.rs): every attribute on op parameters/fields must map to a known modifier (`string`, `buffer`, `number`, `serde`, `smi`, `webidl`, ...), be in the ignore list (`required`, `rename`, `method`, `getter`, `setter`, `fast`, `async_method`, `static_method`, `constructor`, `meta`), or be one of `allow`/`doc`/`cfg` (returned as `None` so external tooling consumes them). Anything else is rejected with `Unknown attribute \`{attr_name}\``.
Source
Thrown at libs/ops/op2/signature.rs:1437
let source = match buf {
"buffer" => BufferSource::TypedArray,
"anybuffer" => BufferSource::Any,
"arraybuffer" => BufferSource::ArrayBuffer,
_ => unreachable!(),
};
Some(AttributeModifier::Buffer(mode, source))
}
// async is a keyword and does not work as #[async] so we use #[async_method] instead
"required" | "rename" | "method" | "getter" | "setter" | "fast"
| "async_method" | "static_method" | "constructor" | "meta" => {
Some(AttributeModifier::Ignore)
}
"allow" | "doc" | "cfg" => None,
attr_name => {
return Err(AttributeError::InvalidAttribute(syn::Error::new(
attr.meta.span(),
format!("Unknown attribute `{attr_name}`"),
)));
}
};
Ok(modifier)
}
fn parse_numeric_type(tp: &Path) -> Result<NumericArg, ArgError> {
if tp.segments.len() == 1 {
let segment = tp.segments.first().unwrap().ident.to_string();
for numeric in NumericArg::iter() {
if Into::<&'static str>::into(numeric) == segment.as_str() {
return Ok(numeric);
}
}
}View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Remove the attribute or replace it with the op2 equivalent (e.g. use `#[serde]` for serde conversion, `#[smi]`/`#[number]` for numerics, `#[string]`/`#[buffer]` for the respective types).
- If the attribute targets another derive, move it onto the type definition, not the op signature.
- Check the exact spelling against the match arms: only `allow`, `doc`, and `cfg` foreign attributes pass through untouched.
Example fix
// before
#[op2]
fn op_fetch(#[cached] #[string] url: String) -> String { /* ... */ }
// after
#[op2]
fn op_fetch(#[string] url: String) -> String { /* ... */ } Defensive patterns
Strategy: validation
Validate before calling
// Compile-time: `cargo check`. Before adding an attribute to an op signature, // verify it appears in op2's match list (libs/ops/op2/signature.rs) or is one of // `allow` / `doc` / `cfg`.
Prevention
- Keep attributes from other derives (serde, validator, ...) on the type definition, not on op parameters.
- After upgrading deno_core, re-check helper-attribute names — renamed modifiers surface as this error.
When it happens
Trigger: Attaching an unrecognized attribute to an op parameter or op item: `#[op2(serializable)]`, `#[op2(cached)]`, `#[param]`, or a helper-attribute typo like `#[stirng]`; also attributes meant for other derives (e.g. a serde attribute on an op2 signature).
Common situations: Mixing serde/validator/clap-style attributes into an op signature; upgrading deno_core where a helper attribute was renamed; typos in the well-known modifiers.
Related errors
- Only ASCII keys are supported
- The flags for this attribute were not sorted alphabetically.
- expected attribute arguments in parentheses: `{}(...)`
- Expected a function or impl block for #[op2]
- duplicate `default` argument
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/919fc7a35876a66f.
Report an issue: GitHub.