jdx/mise · error

`mise lock --upgrade` cannot be combined with tool arguments

Error message

`mise lock --upgrade` cannot be combined with tool arguments

What it means

`mise lock --upgrade` re-resolves every tool already configured in the lockfile itself, so passing explicit tool arguments would be contradictory. mise rejects the combination up front rather than ignoring one of the inputs.

Solutions

  1. Drop the tool arguments: `mise lock --upgrade` upgrades all configured tools
  2. Or drop `--upgrade` and use `mise lock <tool>@<version>` to pin specific tools without the upgrade semantics
  3. Run `mise lock --upgrade` for the full lockfile, then edit individual pins via `mise use <tool>@<version>`

Example fix

// before
mise lock --upgrade node@22 python
// after
mise lock --upgrade
Defensive patterns

Strategy: validation

Validate before calling

// bash: strip tool args when --upgrade is used
if [[ "$*" == *--upgrade* ]]; then set -- mise lock --upgrade; fi

Prevention

When it happens

Trigger: Running `mise lock --upgrade node python` — tool arguments combined with the `--upgrade` flag on `mise lock`.

Common situations: Users habitually appending tool names (as with `mise install`) when upgrading lockfile entries.

Related errors


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

Appendix: source

Thrown at src/cli/lock.rs:351

            dry_run: false,
            platform: vec![],
            bump: false,
            json: true,
            local: false,
            minimum_release_age: None,
            upgrade: false,
        }
        .run_with_installed(Some(installed), config)
        .await
    }

    async fn run_with_installed(
        self,
        installed: Option<&[crate::toolset::ToolVersion]>,
        config: Arc<Config>,
    ) -> Result<()> {
        if self.upgrade && !self.tool.is_empty() {
            bail!("`mise lock --upgrade` cannot be combined with tool arguments");
        }
        let settings = Settings::get();
        let generate = settings.generate_lockfiles();
        let atomic = self.upgrade || generate;
        if !self.dry_run && !atomic {
            lockfile::migrate_monorepo_lockfiles(&config, self.upgrade)?;
        }
        let before_date = self.get_before_date()?;
        let lock_resolve_options = ResolveOptions {
            before_date,
            filter_installed_versions_by_release_date: true,
            latest_versions: self.bump,
            use_locked_version: !self.bump,
            // Lock moving channels to their current concrete value without making
            // ordinary `latest` requests ignore an installed concrete version.
            resolve_rolling_channels: true,
            ..Default::default()
        };

View on GitHub (pinned to 533346cc37)