jdx/mise · error

uv graph locking requires a PyPI package

Error message

uv graph locking requires a PyPI package

What it means

uv graph locking in the pipx backend only supports lockfiles rooted at a PyPI package. lock_requirement parses the tool name as a PipxRequest and, unless it is the Pypi variant, bails: there is no package name to pin `==version` against for uv's resolution graph.

Solutions

  1. Reference the tool as a PyPI package so it parses as PipxRequest::Pypi (e.g. `pipx:ruff` rather than a path/git form).
  2. Disable uv dependency locking for this tool (set the uvx-disable option or `[settings.pypi] uvx = false`) if locking is not required.
  3. Install the tool through a different backend suited to non-PyPI sources (aqua, github, etc.).

Example fix

// before (non-PyPI source, cannot be uv-locked)
[tools]
mytool = "pipx:github:org/mytool"

// after (PyPI package, lockable)
[tools]
mytool = "pipx:mytool"
Defensive patterns

Strategy: validation

Validate before calling

if (!/^pipx:[a-z0-9_.-]+$/i.test(toolRef)) console.warn('uv locking requires a plain PyPI package reference');

Prevention

When it happens

Trigger: Thrown from lock_requirement when the tool_name parses to a non-Pypi PipxRequest (e.g. a bare executable/uvx-style tool or a local path tool) while a uv dependency lock is being built or replayed via resolve_uv_lock/install_uv_lock.

Common situations: A user tries to lock a tool that is not a plain PyPI package (e.g. `pipx:github:some/repo` style or a locally referenced tool) with dependency locking enabled; config misuses the pypi lock feature for non-registry tools.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/backend/pipx/lock.rs:166

    pub(crate) async fn bind_uv_python(
        &self,
        config: &Arc<Config>,
        tv: &mut ToolVersion,
    ) -> Result<()> {
        let python = self.spawnable_dependency(config, None, "python").await
            .ok_or_else(|| eyre!("Python graph installs require an installed interpreter; run `mise install python`"))?;
        let identity = if let Some(identity) = self.configured_python_identity(config).await {
            identity
        } else {
            CmdLineRunner::new(&python).args(["-I", "-c", "import sys, sysconfig; print((sys.implementation.name, sys.version_info[:2], sysconfig.get_config_var('SOABI'), sysconfig.get_platform()))"]).read().await?.trim().to_owned()
        };
        tv.uv_python = Some((python, identity));
        Ok(())
    }

    fn lock_requirement(&self, tv: &ToolVersion) -> Result<String> {
        let PipxRequest::Pypi(package) = self.tool_name().parse()? else {
            bail!("uv graph locking requires a PyPI package");
        };
        let raw = tv.request.options();
        let opts = PipxOptions::new(&raw);
        Ok(format!(
            "{package}{}=={}",
            opts.extras().map(|v| format!("[{v}]")).unwrap_or_default(),
            tv.version
        ))
    }

    fn lock_requirements(&self, tv: &ToolVersion) -> Result<Vec<String>> {
        let raw = tv.request.options();
        let opts = PipxOptions::new(&raw);
        let mut requirements = vec![self.lock_requirement(tv)?];
        requirements.extend(opts.with()?);
        requirements.extend(opts.expose()?);
        Ok(requirements)
    }

View on GitHub (pinned to 533346cc37)