jdx/mise · error

packslip: list_identity_prefix must be a non-empty string

Error message

packslip: list_identity_prefix must be a non-empty string

What it means

packslip's `for_release_list` applies per-call overrides to a verification policy when listing releases. When an override supplies a `list_identity_prefix` it must be a non-empty string, because an empty or whitespace-only prefix would make the identity constraint meaningless (matching every identity) and silently weaken trust verification. The function rejects empty, non-string (e.g. numeric or boolean) TOML values with this error.

Source

Thrown at src/backend/packslip.rs:462

        return Ok(Pin::Identity(explicit));
    }
    match Policy::for_project(project) {
        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. Set `list_identity_prefix` to a non-empty string, e.g. the identity prefix used in the vendor's signing certificate
  2. Remove the `list_identity_prefix` key entirely if you don't need to narrow the list's identity constraint
  3. Check that templating/env interpolation used for the value isn't resolving to an empty string

Example fix

// before
[tools."packslip:acme"]
list_identity_prefix = ""
// after
[tools."packslip:acme"]
list_identity_prefix = "acme-release-signer"
Defensive patterns

Strategy: validation

Validate before calling

let prefix = opts.get("list_identity_prefix");
if let Some(p) = prefix {
    if !p.is_string() || p.as_str().unwrap().trim().is_empty() {
        return Err("list_identity_prefix must be a non-empty string");
    }
}

Type guard

fn is_valid_prefix(v: &toml::Value) -> bool {
    v.as_str().map(|s| !s.trim().is_empty()).unwrap_or(false)
}

Prevention

When it happens

Trigger: Calling `release_list`/`github_list` (or the test helper `release_list_policy_rejects_invalid_overrides`) with packslip options where the `list_identity_prefix` opts entry is `""`, a whitespace-only string like `" "`, or a non-string TOML value (integer, bool, array).

Common situations: A user sets `list_identity_prefix = ""` or leaves it blank in mise.toml while configuring a packslip backend pin; templating or env interpolation resolves to an empty string; a user pastes a config example where the prefix was meant to be filled in.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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