{"record":{"id":"7541270576e3de10","repo":"ducaale/xh","slug":"message-signature-duplicate-covered-component-identifier","errorCode":null,"errorMessage":"message-signature: Duplicate covered component identifier: {}","messagePattern":"message-signature: Duplicate covered component identifier: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/message_signature.rs","lineNumber":157,"sourceCode":"            HeaderValue::from_str(&value)?,\n        );\n    }\n    Ok(())\n}\n\nfn build_signature_params(components: &[String]) -> Result<HttpSignatureParams> {\n    let mut component_ids = Vec::new();\n    let mut seen = HashSet::new();\n    for c in components {\n        let normalized = normalize_component_id(c);\n        let id = HttpMessageComponentId::try_from(normalized.as_str())\n            .with_context(|| format!(\"message-signature: Invalid component: {}\", c))?;\n        // RFC 9421 requires each covered component identifier to appear at most once.\n        // Equivalence is based on component id semantics, where parameter order does\n        // not create a distinct identifier.\n        let uniqueness_key = component_uniqueness_key(&id);\n        if !seen.insert(uniqueness_key) {\n            bail!(\n                \"message-signature: Duplicate covered component identifier: {}\",\n                id\n            );\n        }\n        component_ids.push(id);\n    }\n    HttpSignatureParams::try_new(&component_ids)\n        .context(\"message-signature: Failed to create signature params\")\n}\n\n/// Build a canonical key for RFC 9421 component-identifier uniqueness checks.\n///\n/// RFC 9421 treats component identifiers as unique entries in covered components,\n/// and two identifiers that differ only by parameter ordering are equivalent.\n/// We normalize:\n/// - component name (`HttpField` lowercased, derived names preserved), and\n/// - parameters (sorted, then joined),\n///","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/ducaale/xh/blob/2404aceecc08b0b2d100fedc96f57745cd5904dc/src/message_signature.rs#L139-L175","documentation":"During HTTP message signature construction (RFC 9421), the covered-components list must contain each component identifier at most once. build_signature_params compares semantic uniqueness keys (parameter order ignored) and bails if the same component id appears twice.","triggerScenarios":"Calling sign_request (directly or via tests) with a covered-components list containing a repeated identifier, even with different parameter ordering that is semantically equivalent.","commonSituations":"Hand-written @method/@target-uri lists that duplicate an entry; programmatic assembly that appends default components already present; config merging that concatenates component lists.","solutions":["Deduplicate the covered-components list before signing","Compare components by their semantic uniqueness key, ignoring parameter order","Reject or merge duplicate component specs at configuration load time"],"exampleFix":"// before\nlet components = vec![\"@method\", \"@target-uri\", \"@method\"];\nsign_request(&req, &components, ...)?;\n// after\nlet components: Vec<_> = dedup_by_uniqueness_key(vec![\"@method\", \"@target-uri\", \"@method\"]);\nsign_request(&req, &components, ...)?;","handlingStrategy":"validation","validationCode":"// validate covered components before sign_request\nfn has_duplicates(ids: &[&str]) -> bool {\n    let mut seen = std::collections::HashSet::new();\n    ids.iter().any(|id| !seen.insert(normalize_component_id(id)))\n}\nif has_duplicates(&components) { eprintln!(\"duplicate covered component\"); }","typeGuard":null,"tryCatchPattern":"match sign_request(&req, &components, &key) {\n    Ok(signed) => /* ... */,\n    Err(e) if e.to_string().contains(\"Duplicate covered component\") => {\n        eprintln!(\"deduplicate covered components and retry\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Deduplicate the covered-components list at config load time","Treat parameter-order variants of the same id as equal","Add unit tests asserting uniqueness of component lists","Build component lists programmatically with a set"],"tags":["http","signature","rfc9421","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"2404aceecc08b0b2d100fedc96f57745cd5904dc","analyzedAt":"2026-09-13T19:13:33.814Z","contentChangedAt":"2026-09-13T19:13:33.814Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}