{"record":{"id":"06d93eea915a1bd5","repo":"yewstack/yew","slug":"invalid-attribute-key","errorCode":null,"errorMessage":"invalid attribute key","messagePattern":"invalid attribute key","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/yew/src/dom_bundle/btag/attributes.rs","lineNumber":176,"sourceCode":"                None => true,\n            } {\n                Self::set(el, k, new);\n            }\n        }\n\n        // Remove missing\n        for (k, old_value) in old.iter() {\n            if !new.contains_key(k) {\n                Self::remove(el, k, old_value);\n            }\n        }\n    }\n\n    fn set(el: &Element, key: &str, value: &AttributeOrProperty) {\n        match value {\n            AttributeOrProperty::Attribute(value) => el\n                .set_attribute(intern(key), value)\n                .expect(\"invalid attribute key\"),\n            AttributeOrProperty::Property(value) => {\n                let key = JsValue::from_str(key);\n                js_sys::Reflect::set(el.as_ref(), &key, value).expect(\"could not set property\");\n            }\n        }\n    }\n\n    /// Applies a value during hydration.\n    ///\n    /// Hydration assumes the DOM already matches the server-rendered HTML, so\n    /// attributes are left untouched: re-writing them would needlessly trigger\n    /// side effects. In debug builds we only assert that the existing attribute\n    /// matches the expected value. Properties are not reflected in the HTML, so\n    /// they are always set.\n    #[cfg(feature = \"hydration\")]\n    fn hydrate_set(el: &Element, key: &str, value: &AttributeOrProperty) {\n        match value {\n            AttributeOrProperty::Attribute(value) => {","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/yewstack/yew/blob/0e4a05472fac4e5fce1befe60fa4a1e43a36b6a3/packages/yew/src/dom_bundle/btag/attributes.rs#L158-L194","documentation":"AttributeWriter::set (packages/yew/src/dom_bundle/btag/attributes.rs:176) forwards the attribute name to Element::set_attribute and unwraps with .expect(\"invalid attribute key\"). set_attribute throws InvalidCharacterError when the name is not a valid attribute name: empty, or containing space, quote, '<', '>', '/', '=', or control characters. Literal names from the html! macro are always valid, so this panic almost always comes from dynamically built attribute names (spread attributes, attribute maps) into which invalid characters leaked.","triggerScenarios":"Inserting an attribute whose key is built at runtime and contains invalid characters, e.g. Attributes::insert(format!(\"{name} x\"), ...) or an empty-string key; spreading props whose keys are derived from user input without validation.","commonSituations":"Generic 'rest props' spread components that pass through arbitrary keys; building data-* or aria-* names by string concatenation where a segment is empty or has whitespace; deserializing attribute maps from JSON/config that includes invalid names.","solutions":["Validate or sanitize attribute names before they enter the VTag attribute set: reject empty strings and characters ' \" < > / = and control chars","Fix the code that constructs the offending key (the panic is a symptom; find which name is invalid by logging the key before set)","Restrict dynamic names to a known-safe allowlist (data-, aria-, or your fixed set)"],"exampleFix":"// before\nlet key = format!(\"{} label\", user_part);\nattrs.insert(key, \"1\".into());\n\n// after\nfn is_valid_attr_name(name: &str) -> bool {\n    !name.is_empty() && !name.chars().any(|c| matches!(c, ' ' | '\"' | '\\'' | '<' | '>' | '/' | '=' ) || c.is_control())\n}\nassert!(is_valid_attr_name(&key));\nattrs.insert(key, \"1\".into());","handlingStrategy":"validation","validationCode":"fn is_valid_attr_name(name: &str) -> bool {\n    !name.is_empty()\n        && !name.chars().any(|c| matches!(c, ' ' | '\"' | '\\'' | '<' | '>' | '/' | '=') || c.is_control())\n}\n\n// apply before inserting dynamic attribute names\nif !is_valid_attr_name(&key) {\n    log::warn!(\"dropping invalid attribute name: {key:?}\");\n} else {\n    attrs.insert(key.into(), value.into());\n}","typeGuard":"fn safe_attr_name(name: &str) -> Option<&str> { is_valid_attr_name(name).then_some(name) }","tryCatchPattern":null,"preventionTips":["Prefer static attribute names in html! and pass values dynamically","Validate names at the trust boundary when attribute maps come from JSON, CMS, or user input","Log every dynamically built key once in debug builds to catch typos early"],"tags":["rust","wasm","yew","dom","attributes","runtime-panic"],"backgroundTag":"invalid-dom-attribute-name","analyzedSha":"0e4a05472fac4e5fce1befe60fa4a1e43a36b6a3","analyzedAt":"2026-08-22T21:16:31.212Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}