jdx/mise · error

packslip: list_identity_prefix cannot be combined with pubke

Error message

packslip: list_identity_prefix cannot be combined with pubkey

What it means

`for_release_list` only allows `list_identity_prefix` on an Identity-based policy (issuer + identity-prefix trust). If the active policy is a raw pubkey pin, a prefix override cannot apply — the two trust modes are mutually exclusive — so mise refuses the combination rather than silently ignoring one side. This prevents a config that looks like it narrows trust but actually verifies against a pubkey.

Source

Thrown at src/backend/packslip.rs:465

        Some(policy) => Ok(Pin::Identity(policy)),
        None => bail!(
            "packslip:{project} is not on a forge mise knows, so nothing pins its signer; set `pubkey`, or `identity` and `issuer`, in its tool options"
        ),
    }
}

impl Pin {
    /// A vendor may publish its index from a different workflow than its bundles.
    /// The override replaces only the list's subject constraint, retaining the issuer.
    fn for_release_list(&self, opts: &PackslipOptions<'_>) -> Result<Self> {
        let Some(value) = opts.raw.opts.get("list_identity_prefix") else {
            return Ok(self.clone());
        };
        let Some(prefix) = value.as_str().filter(|prefix| !prefix.trim().is_empty()) else {
            bail!("packslip: list_identity_prefix must be a non-empty string");
        };
        let Self::Identity(policy) = self else {
            bail!("packslip: list_identity_prefix cannot be combined with pubkey");
        };
        if policy.issuer.as_deref().is_none_or(str::is_empty) {
            bail!("packslip: list_identity_prefix requires an issuer");
        }
        Ok(Self::Identity(Policy {
            issuer: policy.issuer.clone(),
            identity: None,
            identity_prefix: Some(prefix.to_string()),
        }))
    }

    fn trust(&self) -> Trust<'_> {
        match self {
            Pin::Identity(policy) => Trust::Identity(policy),
            Pin::Key(key) => Trust::Key(key),
        }
    }
}

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Remove the `list_identity_prefix` override, since a pubkey pin doesn't use an identity prefix
  2. Switch the pin to identity-based trust (issuer + optional prefix) if you want to constrain by identity prefix instead of a literal pubkey
  3. Use only one trust mechanism: either pubkey or identity configuration, not both

Example fix

// before
[tools."packslip:acme"]
pubkey = "sha256:AAAA..."
list_identity_prefix = "acme"
// after
[tools."packslip:acme"]
pubkey = "sha256:AAAA..."
Defensive patterns

Strategy: validation

Validate before calling

const hasPubkey = cfg.pubkey != null;
const hasPrefix = cfg.list_identity_prefix != null;
if (hasPubkey && hasPrefix) throw new Error("pubkey and list_identity_prefix are mutually exclusive");

Type guard

fn uses_identity_policy(policy: &Policy) -> bool {
    matches!(policy, Policy::Identity { .. })
}

Prevention

When it happens

Trigger: Calling `release_list` or `github_list` with a packslip pin that resolves to `Policy::Identity`'s opposite variant (pubkey-based trust) while an override sets `list_identity_prefix` in the packslip options.

Common situations: A vendor's mise.toml pins the release list with a raw pubkey, and the user (or a copied config snippet) also sets `list_identity_prefix`; someone migrates config from identity-prefix style to pubkey pinning but keeps the old prefix key.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/4812b1cfc61b2583. Report an issue: GitHub.