{"record":{"id":"d8c1a58cc4422c94","repo":"jdx/mise","slug":"the-stamp-list-at-url-is-for-not-project","errorCode":null,"errorMessage":"the stamp list at {url} is for {}, not {project}","messagePattern":"the stamp list at (.+?) is for (.+?), not (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/packslip_stamps.rs","lineNumber":302,"sourceCode":"    for stamper in &stampers {\n        let url = stamper.url(project);\n        let text = match HTTP_FETCH.get_text(&url).await {\n            Ok(text) => text,\n            Err(err) if is_not_found(&err) => {\n                missing_list(&stamper.host, project, &url)?;\n                debug!(\"{}: no stamp list for {project} at {url}\", stamper.host);\n                stamps.hosts.push(stamper.host.clone());\n                continue;\n            }\n            Err(err) => {\n                return Err(err)\n                    .wrap_err_with(|| format!(\"fetching the stamp list for {project} from {url}\"));\n            }\n        };\n        let list = verify_release_list(&text, &stamper.pin, true)\n            .wrap_err_with(|| format!(\"verifying the stamp list from {}\", stamper.host))?;\n        if list.predicate.project != project {\n            bail!(\n                \"the stamp list at {url} is for {}, not {project}\",\n                list.predicate.project\n            );\n        }\n        check_sequence(&stamper.host, project, &list)?;\n        stamps.add(&stamper.host, &list);\n    }\n    Ok(Some(stamps))\n}\n\nfn is_not_found(err: &eyre::Report) -> bool {\n    crate::http::error_code(err) == Some(404)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use packslip::model::{","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/packslip_stamps.rs#L284-L320","documentation":"After verifying a stamp list's signature, mise checks that the list's embedded project identifier matches the project actually being resolved. A list signed for a different project is rejected to prevent cross-project stamp substitution.","triggerScenarios":"fetch (via get_or_try_init_async / refresh_async) retrieves and verifies a stamp list from a stamper whose list.predicate.project differs from the requested project parameter.","commonSituations":"Misconfigured stamper host serving a shared or wrong list file; URL points at another project's list; host template expanded incorrectly so the list for project A is fetched when project B was requested.","solutions":["Point the stamper URL at the correct project's stamp list","Fix the stamper host's URL template so {project} resolves correctly","Verify the host publishes a dedicated list per project"],"exampleFix":"// before: URL template missing project substitution\nurl = \"https://stamps.example.com/lists/latest\"\n// after\nurl = \"https://stamps.example.com/lists/{project}/latest\"","handlingStrategy":"validation","validationCode":"let list = fetch_stamp_list_raw(stamper, project)?;\nif list.predicate.project != project {\n    return Err(format!(\"stamper URL serves list for {}, wanted {project}\", list.predicate.project));\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"is for\") && e.to_string().contains(\"not\") => fix_stamper_url_template(stamper)?,\n    other => other?,\n}","preventionTips":["Ensure stamper URL templates substitute the project correctly","Verify host serves one list file per project","Test new stamper hosts with a known project before rollout","Don't share a single list URL across multiple projects"],"tags":["security","packslip","stamps","mismatch"],"backgroundTag":"unexpected-response-shape","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}