jdx/mise · error

the packslip names an artifact {:?}, which is not a plain fi

Error message

the packslip names an artifact {:?}, which is not a plain file name

What it means

Thrown by `install_payload` in the packslip backend when the manifest names an artifact whose `name` is not a plain file name (per `file::is_plain_file_name` — e.g. it contains path separators, `..`, or otherwise looks like a path). mise rejects such names before constructing the download path, preventing path traversal or unsafe file placement inside the install directory.

Source

Thrown at src/backend/packslip.rs:1235

        let mut commands = BTreeMap::new();
        if let Some(req) = &artifact.requires {
            for bin in &req.bin {
                // Spawnable, not merely present: the probe below runs the
                // path with `--version`, so a shebang-only script or a `.ps1`
                // would be chosen and then fail to start.
                if let Some(path) = ctx.ts.which_bin_spawnable(&ctx.config, &bin.name).await {
                    commands.insert(bin.name.clone(), path);
                }
            }
        }
        crate::packslip_requirements::check(&artifact, &commands)
            .await
            .enforce(raw_opts.get("ignore_requirements") == Some("true"))?;
        let Some(url) = artifact.url.clone() else {
            bail!("the packslip gives no download URL for {}", artifact.name);
        };
        if !file::is_plain_file_name(&artifact.name) {
            bail!(
                "the packslip names an artifact {:?}, which is not a plain file name",
                artifact.name
            );
        }
        let file_path = tv.download_path().join(&artifact.name);
        ctx.pr.next_operation();
        ctx.pr.set_message(format!("download {}", artifact.name));
        HTTP.download_file_with_headers(
            &url,
            &file_path,
            &headers_for(&url)?,
            Some(ctx.pr.as_ref()),
        )
        .await?;

        // The signed digest and size first, then what the lockfile remembers:
        // a lock entry written from an earlier packslip keeps its checksum and
        // is compared, so a newly signed manifest cannot quietly replace what

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Upgrade or downgrade the tool version so the packslip manifest uses plain artifact file names (`mise use packslip:owner/repo@<version>`).
  2. Inspect the manifest's artifact names for your platform; if they embed paths, report the malformed packslip to the upstream project.
  3. Use an alternate backend with well-formed asset names (`mise use aqua:owner/repo` or `mise use github:owner/repo`).
  4. If you control the packslip generation, fix the publisher to emit bare file names for each artifact.

Example fix

// upstream packslip manifest artifact entry
// before
{ "name": "dist/mytool-linux-amd64.tar.gz", "url": "..." }
// after
{ "name": "mytool-linux-amd64.tar.gz", "url": "..." }
Defensive patterns

Strategy: validation

Validate before calling

// reject artifact names with path separators before installing
const isPlain = name && !name.includes('/') && !name.includes('\\') && name !== '.' && name !== '..';
if (!isPlain) throw new Error(`artifact name ${name} is not a plain file name`);

Type guard

function isPlainFileName(name) { return typeof name === 'string' && /^[^/\\]+$/u.test(name) && name !== '.' && name !== '..'; }

Try / catch

try { await $`mise install` } catch (e) { if (String(e).includes('not a plain file name')) { /* switch backend or report upstream manifest */ } else throw e; }

Prevention

When it happens

Trigger: Installing a packslip-backed tool where the manifest's artifact `name` for your platform contains characters like `/`, `\`, or leading directories (e.g. `"bin/tool.tar.gz"` or `"../tool"`) so `is_plain_file_name` returns false.

Common situations: An upstream project publishes signed manifests where artifact names include subpaths; a maliciously or accidentally crafted manifest; platform-specific artifacts named with directory prefixes; manifest format drift after a publisher tooling change.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


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