nikivdev/code · error · anyhow::Error

git config --global --unset-all {} failed

Error message

git config --global --unset-all {} failed

What it means

git_config_unset_all runs `git config --global --unset-all <key> <value>` (used by remove_url_rewrite to delete matching multi-valued entries) and bails if git exits nonzero. Note git also exits nonzero when the key/value is simply not present, so a no-op cleanup can surface as this error.

Source

Thrown at src/ssh.rs:485

        .args(["config", "--global", "--add", key, value])
        .status()
        .context("failed to run git config")?;

    if !status.success() {
        anyhow::bail!("git config --global --add {} failed", key);
    }

    Ok(())
}

fn git_config_unset_all(key: &str, value: &str) -> Result<()> {
    let status = Command::new("git")
        .args(["config", "--global", "--unset-all", key, value])
        .status()
        .context("failed to run git config")?;

    if !status.success() {
        anyhow::bail!("git config --global --unset-all {} failed", key);
    }

    Ok(())
}

fn add_url_rewrite(key: &str, desired: &[&str]) -> Result<bool> {
    let existing = git_config_get_all(key)?;
    let mut changed = false;

    for value in desired {
        if existing.iter().any(|val| val == value) {
            continue;
        }
        git_config_add(key, value)?;
        changed = true;
    }

    Ok(changed)

View on GitHub (pinned to a747e741ae)

Solutions

  1. Treat git's 'nothing to unset' exit code (5) as success so cleanup is idempotent
  2. Check whether the key/value actually exists with `git config --global --get-all <key>`
  3. Remove stale ~/.gitconfig.lock and verify the config parses
  4. Ensure HOME is writable in the execution environment

Example fix

// before: any nonzero exit is an error
if !status.success() {
    anyhow::bail!("git config --global --unset-all {} failed", key);
}
// after: tolerate 'nothing to unset'
if !status.success() && status.code() != Some(5) {
    anyhow::bail!("git config --global --unset-all {} failed", key);
}
Defensive patterns

Strategy: validation

Validate before calling

fn rewrite_exists(key: &str, value: &str) -> bool {
    std::process::Command::new("git")
        .args(["config", "--global", "--get-all", key, value])
        .output()
        .map(|o| o.status.success()).unwrap_or(false)
}
// only attempt unset when the entry actually exists
if rewrite_exists(key, value) { remove_url_rewrite(key)?; }

Try / catch

match remove_url_rewrite(key) {
    Ok(_) => println!("rewrite removed (or already absent)"),
    Err(e) if e.to_string().contains("--unset-all") => {
        // git exits 5 when there is nothing to unset — treat as idempotent success
        eprintln!("unset failed: {e:#}; entry may not exist");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: remove_url_rewrite calls git_config_unset_all when the global config is unwritable/corrupt, HOME is misconfigured, a config.lock exists — or when no matching entry exists so git returns exit code 5 (nothing to unset).

Common situations: Trying to remove a rewrite that was never added (idempotent cleanup treated as failure); CI environments with read-only HOME; leftover config.lock; malformed gitconfig preventing parsing.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/4418748002c03310. Report an issue: GitHub.