jdx/mise · error

`auth` for {key} is not `user:password`

Error message

`auth` for {key} is not `user:password`

What it means

When mise reads Docker-style credentials (for `mise oci push`/registry auth) from ~/.docker/config.json, an entry's `auth` field must be base64 of `user:password`. After successful base64 decode and UTF-8 validation, the value must contain a colon; a decoded string without one (e.g. a bare API token) violates the format and fails here. Note that a valid `identitytoken` field takes precedence and bypasses this path.

Source

Thrown at src/oci/auth.rs:177

            Err(e) => {
                debug!("credsStore helper {helper} has no credentials for {registry}: {e}");
            }
        }
    }

    Ok(None)
}

fn credential_from_entry(entry: &AuthEntry, key: &str) -> Result<Option<Credential>> {
    let (mut username, mut secret) = (entry.username.clone(), entry.password.clone());
    if let Some(auth) = entry.auth.as_deref().filter(|a| !a.is_empty()) {
        let decoded = BASE64_STANDARD
            .decode(auth.trim())
            .wrap_err_with(|| format!("decoding base64 `auth` for {key}"))?;
        let decoded = String::from_utf8(decoded)
            .wrap_err_with(|| format!("`auth` for {key} is not valid UTF-8"))?;
        let Some((u, p)) = decoded.split_once(':') else {
            bail!("`auth` for {key} is not `user:password`");
        };
        username = Some(u.to_string());
        secret = Some(p.to_string());
    }
    // An identity token (docker.io "Docker Desktop" login flow) replaces the
    // password; the username from `auth` is ignored by registries in this
    // mode but `<token>` is the conventional placeholder.
    if let Some(token) = entry.identity_token.as_deref().filter(|t| !t.is_empty()) {
        return Ok(Some(Credential {
            username: "<token>".to_string(),
            secret: token.to_string(),
        }));
    }
    match (username, secret) {
        (Some(u), Some(p)) => Ok(Some(Credential {
            username: u,
            secret: p,
        })),

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Re-run `docker login <server>` so a spec-conformant user:password auth entry is written
  2. Replace the `auth` field with explicit `"username"` and `"password"` fields in config.json
  3. If the secret is a registry identity token, put it in `"identitytoken"` (mise maps it to username `<token>`) instead of `auth`
  4. Delete the malformed entry so mise falls back to other credential sources

Example fix

# before (~/.docker/config.json)
{
  "auths": {
    "ghcr.io": { "auth": "Z2hwX3Rva2VuMTIzNDU2Nzg5" }
  }
}

# after
{
  "auths": {
    "ghcr.io": {
      "username": "myuser",
      "password": "ghp_token123456789"
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

python3 - <<'EOF'
import json, base64, sys
cfg = json.load(open('$HOME/.docker/config.json'))
for key, entry in {**cfg.get('auths', {})}.items():
    auth = entry.get('auth')
    if auth:
        try: decoded = base64.b64decode(auth).decode('utf-8')
        except Exception as e: sys.exit(f'{key}: auth not base64/UTF-8: {e}')
        if ':' not in decoded: sys.exit(f'{key}: auth decodes without user:password colon')
print('docker auth entries OK')
EOF

Type guard

fn auth_is_user_password(auth_b64: &str) -> bool {
    base64::engine::general_purpose::STANDARD
        .decode(auth_b64.trim()).ok()
        .and_then(|b| String::from_utf8(b).ok())
        .map(|s| s.split_once(':').is_some())
        .unwrap_or(false)
}

Try / catch

Catch this per-server before OCI push; on trigger, skip the entry (fall back to anonymous or explicit username/password) and log which registry key needs re-login, rather than aborting the whole push.

Prevention

When it happens

Trigger: A config.json `auth` value that base64-decodes to a token or username with no ':' separator — commonly written by third-party CLIs, cloud helpers, or manual base64 encoding of registry tokens. Hit during any OCI registry authentication when mise parses the auth entry for that server key.

Common situations: Registries whose CLI stores `echo -n <token> | base64` instead of `echo -n user:token | base64`; hand-crafted config.json entries; GitLab/GHCR deploy tokens pasted incorrectly.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/f2f803af38068eff. Report an issue: GitHub.