jdx/mise · error

the release list at is for , not

Error message

the release list at {url} is for {}, not {project}

What it means

The signed release list fetched from the configured URL verifies cryptographically, but its predicate.project does not match the packslip project being resolved. mise treats a list signed for a different project as unusable for this one, preventing cross-project list substitution.

Solutions

  1. Fix the release list URL in the tool options so it points to the list for this exact project.
  2. Remove a custom list_url option to use the packslip's default list location.
  3. Verify the project name in mise.toml matches the vendor's packslip project id exactly.
  4. Contact the vendor if their published packslip genuinely points at the wrong project's list.

Example fix

// before
"packslip:foo" = { version = "1.0", release_list_url = "https://vendor.example/other-tool.list.json" }

// after
"packslip:foo" = { version = "1.0", release_list_url = "https://vendor.example/foo.list.json" }
Defensive patterns

Strategy: validation

Validate before calling

// Verify the fetched list belongs to the expected project.
const list = JSON.parse(listText);
if (list.predicate.project !== expectedProject) {
  throw new Error(`list is for ${list.predicate.project}, expected ${expectedProject}`);
}

Type guard

const isListFor = (list, project) => list?.predicate?.project === project;

Prevention

When it happens

Trigger: release_list (called from vendor_entry, recommendation, vendor_versions) after verify_release_list succeeds but list.predicate.project != project for the fetched URL.

Common situations: A misconfigured or templated release-list URL pointing at another project's list; a vendor reusing a list URL across renamed projects; copy-pasting a list_url option from a different tool's config.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/fec1f70a86dcea2e. Report an issue: GitHub.

Appendix: source

Thrown at src/backend/packslip.rs:736

    fn repo(project: &str) -> Option<String> {
        repository(project).map(|(_, owner, repo)| format!("{owner}/{repo}"))
    }

    async fn release_list(
        &self,
        project: &str,
        pin: &Pin,
        opts: &PackslipOptions<'_>,
    ) -> Result<ReleaseListStatement> {
        let pin = pin.for_release_list(opts)?;
        let url = well_known_url(project);
        let text = HTTP_FETCH.get_text(&url).await.wrap_err_with(|| {
            format!("fetching the release list of packslip:{project} from {url}")
        })?;
        let list = verify_release_list(&text, &pin, !opts.allow_unlogged())
            .wrap_err_with(|| format!("verifying the release list of packslip:{project}"))?;
        if list.predicate.project != project {
            bail!(
                "the release list at {url} is for {}, not {project}",
                list.predicate.project
            );
        }
        check_sequence(project, &list)?;
        Ok(list)
    }

    /// The signed list a github.com repository may keep at `.well-known`
    /// on its default branch, verified against its list signer (by default,
    /// the same identity as its packslips). `None` when the repository has
    /// none, which is the usual case: a vendor writes one only to withdraw
    /// a release, flag a security fix, or list a release whose tag names no version.
    async fn github_list(
        &self,
        project: &str,
        repo: &str,
        pin: &Pin,

View on GitHub (pinned to 533346cc37)