jdx/mise · error

command wrapper for {shim_name} cannot delegate to itself

Error message

command wrapper for {shim_name} cannot delegate to itself

What it means

mise allows configuring command wrappers that delegate shim invocations to a different command, but a wrapper whose command equals the shim's own name would recurse infinitely. which_shim detects this self-delegation and aborts before dispatching.

Source

Thrown at src/shims.rs:236

        .with_resolve_options(resolve_options)
        .build(config)
        .await?;
    let wrappers = load_command_wrappers(
        &config.config_files,
        ts.versions.values().flat_map(|versions| &versions.requests),
    )?;
    validate_wrapper_names(wrappers.keys())?;
    let wrapper = if cfg!(macos) {
        wrappers
            .iter()
            .find(|(name, _)| command_names_eq(name, shim_name))
            .map(|(_, wrapper)| wrapper)
    } else {
        wrappers.get(shim_name)
    };
    if let Some(wrapper) = wrapper {
        if command_names_eq(wrapper.command(), shim_name) {
            bail!("command wrapper for {shim_name} cannot delegate to itself");
        }
        trace!("shim[{bin_name}] WRAPPER command: {}", wrapper.command());
        return Ok((PathBuf::from(wrapper.command()), ts, Some(wrapper.clone())));
    }
    // A configured tool may intentionally override an executable bundled by another installed
    // tool (for example, a pinned npm overrides Node's npm). Install a missing provider declared
    // by the registry before resolving an incidental installed provider.
    if !completion_offline
        && Settings::get().not_found_auto_install
        && ts
            .should_install_missing_registry_bin_provider(config, shim_name)
            .await?
    {
        for tv in ts
            .install_missing_bin(config, shim_name)
            .await?
            .unwrap_or_default()
        {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Point the wrapper command at the real underlying executable path (e.g. ~/.local/share/mise/installs/<tool>/.../bin/foo) instead of the bare name.
  2. Rename the wrapper to a different command name than the target tool.
  3. Remove the wrapper if it provides no value and call the tool directly.
  4. Check `mise wrapper list` / relevant config to find the offending wrapper entry.

Example fix

// before (mise.toml)
[wrapper]
node = "node --max-old-space-size=4096" // delegates to itself

// after
[wrapper]
node = "/home/me/.local/share/mise/installs/node/20/bin/node --max-old-space-size=4096"
Defensive patterns

Strategy: validation

Validate before calling

# bash: ensure wrapper command differs from the wrapper name before writing config
name="node"; cmd="node --max-old-space-size=4096"
[ "$name" = "$(echo "$cmd" | awk '{print $1}')" ] && echo "wrapper $name delegates to itself — point it at the real binary path"

Prevention

When it happens

Trigger: Configuring a command wrapper (in mise.toml wrapper/command-wrapper config) for tool `foo` whose resolved command is `foo` itself — e.g. `[wrapper] foo = "foo --flag"` or an absolute path that resolves to the same command name.

Common situations: Users intending to wrap a tool with extra flags but forgetting the wrapper must point at a *different* executable (or a full path to the real tool binary), so the wrapper name and target command collide.

Related errors


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