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

  1. 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).
  2. If the attribute targets another derive, move it onto the type definition, not the op signature.
  3. 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

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


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/919fc7a35876a66f. Report an issue: GitHub.