plandex-ai/plandex · error

error creating git stash: %v, output: %s

Error message

error creating git stash: %v, output: %s

What it means

GitStashCreate runs `git stash push --include-untracked -m <message>` (from the process working directory) to snapshot all changes including untracked files. This error is returned when the stash command exits non-zero, embedding the git error and its combined output.

Source

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

	defer gitMutex.Unlock()

	// Check if there are any changes
	res, err := exec.Command("git", "status", "--porcelain").CombinedOutput()
	if err != nil {
		return false, fmt.Errorf("error checking for uncommitted changes: %v, output: %s", err, string(res))
	}

	// If there's output, there are uncommitted changes
	return strings.TrimSpace(string(res)) != "", nil
}

func GitStashCreate(message string) error {
	gitMutex.Lock()
	defer gitMutex.Unlock()

	res, err := exec.Command("git", "stash", "push", "--include-untracked", "-m", message).CombinedOutput()
	if err != nil {
		return fmt.Errorf("error creating git stash: %v, output: %s", err, string(res))
	}

	return nil
}

// this matches output for git version 2.39.3
// need to test on other versions and check for more variations
// there isn't any structured way to get stash conflicts from git, unfortunately
const PopStashConflictMsg = "overwritten by merge"
const ConflictMsgFilesEnd = "commit your changes"

func GitStashPop(forceOverwrite bool) error {
	gitMutex.Lock()
	defer gitMutex.Unlock()

	res, err := exec.Command("git", "stash", "pop").CombinedOutput()

	// we should no longer have conflicts since we are forcing an update before

View on GitHub (pinned to e2d772072e)

Solutions

  1. Check the wrapped output — 'You do not have the initial commit' means the repo has no commits yet; make an initial commit first.
  2. If unmerged paths exist, resolve/abort them (`git status`, `git merge --abort` or checkout) before stashing.
  3. Ensure the process cwd is inside the repository (this function uses no `-C` flag).
  4. Remove stale .git/index.lock if no git process is active.
  5. Confirm git is installed and on PATH.

Example fix

// before: stash in repo with conflicts pending
lib.GitStashCreate("auto-save")
// after
exec.Command("git", "checkout", "--", ".").Run() // or resolve unmerged paths first
lib.GitStashCreate("auto-save")
Defensive patterns

Strategy: validation

Validate before calling

// Go: check repo health and no unmerged paths before stashing
out, err := exec.Command("git", "status", "--porcelain").Output()
if err != nil { /* not a repo or git missing */ }
if strings.Contains(string(out), "UU") || strings.Contains(string(out), "AA") {
    // resolve conflicts before GitStashCreate
}

Type guard

func isStashCreateError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "error creating git stash")
}

Try / catch

if err := lib.GitStashCreate("pre-update"); err != nil {
    if isStashCreateError(err) {
        log.Printf("stash failed: %v — resolve unmerged paths or check repo state", err)
        // fall back to aborting the update flow rather than proceeding dirty
    }
}

Prevention

When it happens

Trigger: Calling GitStashCreate(message) outside a git repository, with git missing from PATH, when the index is locked, when there are unmerged/conflicted paths that stash refuses to handle, or when untracked files would be clobbered in pathological states.

Common situations: Process started outside the repo working directory; a previous failed stash pop left conflict state (unmerged entries) so stash push fails; container without git; .git/index.lock held by another process.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


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