nikivdev/code · error

Git index lock detected during merge. Remove stale .git/inde

Error message

Git index lock detected during merge. Remove stale .git/index.lock (if no git process is running) and re-run.

What it means

Thrown in src/sync.rs when `git merge --ff-only <remote_ref>` fails and its output matches `is_git_index_lock_error`. Git refuses to run because `.git/index.lock` exists, usually a stale lock left by a crashed or concurrent git process. The message instructs removing the lock only when no git process is running.

Source

Thrown at src/sync.rs:4044

        recorder.record(stage, format!("already up to date with {}", remote_ref));
        return Ok(());
    }

    sync_progressln!("Merging {} commits from {}...", behind, remote_ref);
    recorder.record(
        stage,
        format!("merging {} commits from {}", behind, remote_ref),
    );

    let ff_only_output = git_run_output_in(repo_root, &["merge", "--ff-only", &remote_ref])?;
    if ff_only_output.status.success() {
        recorder.record(stage, format!("fast-forwarded to {}", remote_ref));
        return Ok(());
    }

    let ff_only_detail = git_output_text(&ff_only_output);
    if is_git_index_lock_error(&ff_only_detail) {
        bail!(
            "Git index lock detected during merge. Remove stale .git/index.lock (if no git process is running) and re-run."
        );
    }
    if !is_expected_ff_only_merge_failure(&ff_only_detail) {
        bail!(
            "git merge --ff-only {} failed: {}",
            remote_ref,
            ff_only_detail
        );
    }

    let merge_output = git_run_output_in(repo_root, &["merge", &remote_ref, "--no-edit"])?;
    if merge_output.status.success() {
        recorder.record(stage, format!("merged {} with commit", remote_ref));
        return Ok(());
    }
    let merge_detail = git_output_text(&merge_output);
    if is_git_index_lock_error(&merge_detail) {

View on GitHub (pinned to a747e741ae)

Solutions

  1. Confirm no git process is running: `ps aux | grep git` (also check IDE git integrations).
  2. Remove the stale lock: `rm .git/index.lock`, then re-run sync.
  3. Close IDE/git GUI tools that may hold the index, then retry.
  4. If the lock reappears, investigate what is spawning concurrent git operations (hooks, cron jobs, parallel syncs).

Example fix

// before
f sync
// error: Git index lock detected during merge...

// after
ps aux | grep '[g]it'        # verify nothing is running
rm -f .git/index.lock
f sync
Defensive patterns

Strategy: validation

Validate before calling

import std::path::Path;
if Path::new(".git/index.lock").exists() {
    eprintln!(".git/index.lock exists; ensure no git process is running, then remove it.");
    std::process::exit(1);
}

Type guard

fn index_lock_stale(repo_root: &Path) -> bool {
    repo_root.join(".git/index.lock").exists()
}

Try / catch

match sync::run(&repo_root, &cmd) {
    Err(e) if e.to_string().contains("index.lock") => {
        eprintln!("Stale git index lock. Verify no git process, then: rm .git/index.lock");
    }
    other => other,
}

Prevention

When it happens

Trigger: During sync's fast-forward stage, the ff-only merge exits with an 'Unable to create ... index.lock: File exists' style error. Commonly after a killed git process, an IDE/git GUI holding the index, or two syncs running concurrently.

Common situations: A previous sync was interrupted (Ctrl-C, crash, laptop sleep); a background IDE (VS Code git integration) holds the index; running multiple f sync instances in parallel terminals.

Related errors


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