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 backend: when a tool's options override the release-list pin via list_identity_prefix, the override string was empty. A non-empty prefix is required so mise can constrain the release-list manifest signer by matching subject prefixes against it.

Solutions

  1. Set list_identity_prefix to the intended non-empty prefix string in the tool options.
  2. If the value comes from an env var/template, ensure that variable is set (e.g. in .env or mise.toml [env]).
  3. Remove the list_identity_prefix option entirely if you want the release list's default identity constraint.

Example fix

// before
"packslip:foo" = { version = "1.0", list_identity_prefix = "" }

// after
"packslip:foo" = { version = "1.0", list_identity_prefix = "https://github.com/vendor/" }
Defensive patterns

Strategy: validation

Validate before calling

function validateListIdentityPrefix(opts) {
  const v = opts.list_identity_prefix;
  if (v !== undefined && (typeof v !== 'string' || v.trim() === '')) {
    throw new Error('list_identity_prefix must be a non-empty string');
  }
}

Type guard

const isNonEmptyString = (v) => typeof v === 'string' && v.trim().length > 0;

Prevention

When it happens

Trigger: Calling release_list/github_list with PackslipOptions containing list_identity_prefix set to "", " ", or a non-string value.

Common situations: Empty variable interpolation in mise.toml (env var not set so the option resolves to an empty string); quoting mistakes leaving the value blank; passing a non-string type in config.

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@533346cc37 (2026-09-17). Data as JSON: /api/errors/141cef777693c679. Report an issue: GitHub.

Appendix: source

Thrown at src/backend/packslip.rs:566

        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 533346cc37)