jdx/mise · error

Python locks require credential-free HTTP artifact URLs…

Error message

Python locks require credential-free HTTP artifact URLs; configure authentication outside the lockfile

What it means

validate_portable_urls enforces that every artifact URL recorded in a generated Python (uv) lockfile is an http/https URL with no embedded credentials (username/password) and no query string. Portable locks must work across machines, so credentials cannot be baked into the lockfile; this error signals a URL that would leak or bind authentication into the lock.

Solutions

  1. Remove credentials and query strings from the artifact URLs and configure authentication out-of-band (netrc, keyring, or env-based index auth)
  2. Use a credential-free internal mirror/proxy URL for private artifacts
  3. Regenerate the lock against an index that serves plain https URLs

Example fix

# before (lockfile entry)
url = "https://user:token@pypi.example.com/pkg.whl"
# after
url = "https://pypi.example.com/pkg.whl" # auth via netrc/env
Defensive patterns

Strategy: validation

Validate before calling

// validate a lockfile artifact URL before use
const u = new URL(url);
const ok = (u.protocol === 'https:' || u.protocol === 'http:') && !u.username && !u.password && u.search === '';

Prevention

When it happens

Trigger: Validating a uv lock (validate_uv_lock) or a lock entry's URL when the artifact URL contains userinfo (user:pass@), a password, or a query parameter, or uses a non-http(s) scheme.

Common situations: Pointing the lock at a private package index whose artifact URLs embed basic-auth credentials; using a mirror that appends tokens as query strings; hand-editing a lockfile with a credentialed internal registry URL.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

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

    {
        url.set_path("/simple/");
    } else {
        let path = url.path().trim_end_matches('/').trim_end_matches("/simple");
        url.set_path(&format!("{path}/simple/"));
    }
    Ok(url.into())
}

fn validate_portable_urls(value: &toml::Value) -> Result<()> {
    match value {
        toml::Value::String(s) if s.contains("://") => {
            let url = url::Url::parse(s)?;
            if !matches!(url.scheme(), "https" | "http")
                || !url.username().is_empty()
                || url.password().is_some()
                || url.query().is_some()
            {
                bail!(
                    "Python locks require credential-free HTTP artifact URLs; configure authentication outside the lockfile"
                );
            }
        }
        toml::Value::Table(t) => {
            for value in t.values() {
                validate_portable_urls(value)?;
            }
        }
        toml::Value::Array(a) => {
            for value in a {
                validate_portable_urls(value)?;
            }
        }
        _ => (),
    }
    Ok(())
}

View on GitHub (pinned to 533346cc37)