{"record":{"id":"5fe6ce27a9f941d1","repo":"swc-project/swc","slug":"duplicateattribute","errorCode":"DuplicateAttribute","errorMessage":"Duplicate attribute","messagePattern":"Duplicate attribute","errorType":"validation","errorClass":"swc_xml_parser::error::Error","httpStatus":null,"severity":"error","filePath":"crates/swc_xml_parser/src/lexer/mod.rs","lineNumber":820,"sourceCode":"    }\n\n    fn emit_tag_token(&mut self, kind: Option<TagKind>) {\n        if let Some(mut current_tag_token) = self.current_tag_token.take() {\n            if let Some(kind) = kind {\n                current_tag_token.kind = kind;\n            }\n\n            let mut already_seen: FxHashSet<Atom> = Default::default();\n\n            let attributes = current_tag_token\n                .attributes\n                .drain(..)\n                .map(|attribute| {\n                    let name = Atom::from(attribute.name);\n\n                    if already_seen.contains(&name) {\n                        self.errors\n                            .push(Error::new(attribute.span, ErrorKind::DuplicateAttribute));\n                    }\n\n                    already_seen.insert(name.clone());\n\n                    AttributeToken {\n                        span: attribute.span,\n                        name,\n                        raw_name: attribute.raw_name.map(Atom::from),\n                        value: attribute.value.map(Atom::from),\n                        raw_value: attribute.raw_value.map(Atom::from),\n                    }\n                })\n                .collect();\n\n            match current_tag_token.kind {\n                TagKind::Start => {\n                    let start_tag_token = Token::StartTag {\n                        tag_name: current_tag_token.tag_name.into(),","sourceCodeStart":802,"sourceCodeEnd":838,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_xml_parser/src/lexer/mod.rs#L802-L838","documentation":"The XML lexer collects a tag's attribute names into an FxHashSet while materializing them (crates/swc_xml_parser/src/lexer/mod.rs:820). A name already present in the set yields `DuplicateAttribute` on the second occurrence's span. XML 1.0 forbids duplicate attribute names on a single element (a well-formedness constraint — unlike HTML, where later duplicates are simply dropped); the token still carries all attributes, so downstream code decides the winner.","triggerScenarios":"Parsing any XML via swc_xml_parser where one start tag repeats an attribute name: `<item id=\"1\" id=\"2\"/>`, or where default namespace/prefix serialization accidentally emits the same qualified name twice.","commonSituations":"Dynamically built XML that concatenates two attribute maps; templating engines merging default attributes with user overrides without deduplicating; hand-edited config files; SVG assets exported by tools that repeat attributes (e.g. fill or class).","solutions":["Deduplicate attribute maps before serializing the tag (decide first-wins or last-wins policy)","Fix the source XML by deleting the duplicate attribute","If a template merges defaults with overrides, merge into one map keyed by qualified name before emitting","Add xmllint or an equivalent well-formedness check to CI for XML assets"],"exampleFix":"<!-- before -->\n<item id=\"1\" id=\"2\"/>\n<!-- after -->\n<item id=\"1\"/>","handlingStrategy":"validation","validationCode":"// Deduplicate attributes before emitting XML (last-wins policy)\nfunction serializeTag(name: string, attrs: Record<string, string>): string {\n  const seen = new Set<string>();\n  const parts: string[] = [];\n  for (const [k, v] of Object.entries(attrs).reverse()) {\n    const q = k.includes(':') ? k : k; // keep qualified names as-is\n    if (!seen.has(q)) { seen.add(q); parts.unshift(`${q}=\"${v}\"`); }\n  }\n  return `<${name} ${parts.join(' ')}>`;\n}","typeGuard":null,"tryCatchPattern":"let mut parser = swc_xml_parser::parser::Parser::new(lexer);\nlet doc = parser.parse_document()?; // recovers; attributes all retained in token\nfor err in parser.take_errors() {\n    if matches!(err.kind, ErrorKind::DuplicateAttribute) { /* reject or dedupe input */ }\n}","preventionTips":["Merge attribute maps by qualified name before serialization, never concatenate","Run xmllint (well-formedness) on XML assets in CI","Decide a documented first-wins/last-wins policy so dedupe is deterministic"],"tags":["xml","attributes","well-formedness","lexer","duplicate"],"backgroundTag":"xml-wellformedness-error","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}