plandex-ai/plandex · error

error resetting file %s: %v

Error message

error resetting file %s: %v

What it means

During force-overwrite conflict resolution in GitStashPop, each conflicted file is reset via `git checkout --ours <file>`. This error wraps a failure of that per-file checkout, including the file name and git's output. It aborts the conflict-resolution loop, leaving remaining conflicts and the stash un-dropped.

Source

Thrown at app/cli/lib/git.go:154

		log.Println("Error popping git stash:", string(res))

		if strings.Contains(string(res), PopStashConflictMsg) {
			log.Println("Conflicts detected")

			if !forceOverwrite {
				return fmt.Errorf("conflict popping git stash: %s", string(res))
			}

			// Parse the output to find which files have conflicts
			conflictFiles := parseConflictFiles(string(res))

			log.Println("Conflicting files:", conflictFiles)

			for _, file := range conflictFiles {
				// Reset each conflicting file individually
				checkoutRes, err := exec.Command("git", "checkout", "--ours", file).CombinedOutput()
				if err != nil {
					return fmt.Errorf("error resetting file %s: %v", file, string(checkoutRes))
				}
			}
			dropRes, err := exec.Command("git", "stash", "drop").CombinedOutput()
			if err != nil {
				return fmt.Errorf("error dropping git stash: %v", string(dropRes))
			}
			return nil
		} else {
			log.Println("No conflicts detected")

			return fmt.Errorf("error popping git stash: %v", string(res))
		}
	}

	return nil
}

func GitClearUncommittedChanges() error {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Check the file name in the error; run `git -C <repo> checkout --ours -- <file>` manually to see the real error.
  2. If paths look mangled, manually resolve: `git checkout HEAD -- .` or `git reset --hard` then `git stash drop`.
  3. Clear unmerged index entries with `git reset` before retrying the checkout.
  4. Pin/verify the git version behavior against 2.39.3, since parseConflictFiles is version-sensitive.
  5. As a last resort abort resolution: `git reset --hard` + `git stash drop` to restore a clean state.

Example fix

// before: relying on version-sensitive parse
err := lib.GitStashPop(true)
// after: manual recovery on failure
if err := lib.GitStashPop(true); err != nil {
    exec.Command("git", "reset", "--hard").Run()
    exec.Command("git", "stash", "drop").Run()
}
Defensive patterns

Strategy: fallback

Validate before calling

// Go: verify git version matches the format parseConflictFiles expects
out, _ := exec.Command("git", "version").Output()
if !strings.Contains(string(out), "2.39") {
    // prefer manual resolution path instead of forceOverwrite parsing
}

Type guard

func isResetFileError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "error resetting file ")
}

Try / catch

if err := lib.GitStashPop(true); err != nil {
    if isResetFileError(err) {
        // recover: hard reset and drop stash to return to a clean state
        exec.Command("git", "reset", "--hard").Run()
        exec.Command("git", "stash", "drop").Run()
    }
}

Prevention

When it happens

Trigger: GitStashPop(true) hit conflicts and, while resetting each parsed conflict file, `git checkout --ours <file>` failed — typically because the parsed file path is wrong (parseConflictFiles output mismatch on a different git version), the file is unmerged and checkout refuses, or the path no longer exists.

Common situations: Different git versions emit conflict output in a format parseConflictFiles doesn't fully expect (the code itself notes it was only tested against git 2.39.3), yielding mangled file names; files deleted/renamed since the stash; unmerged index entries requiring `git checkout HEAD --` or index reset instead.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/b1ef622cbc00169a. Report an issue: GitHub.