paperclipai/paperclip · info
[paperclip] Workspace restore preserved local working tree c
Error message
[paperclip] Workspace restore preserved local working tree changes after clean sandbox restore.
What it means
resetLocalGitIndexToHead runs `git reset --quiet HEAD -- .` to unstage everything after a sandbox restore, asserts no staged changes remain (throws if staged diff is non-empty), then — only when checkWorkingTreeClean is set — runs `git diff --name-status HEAD`. Non-empty output means the restore left unstaged working-tree modifications, which the helper intentionally does NOT discard; this console.warn says those local changes were preserved through the clean-restore flow.
Source
Thrown at packages/adapter-utils/src/git-workspace-sync.ts:638
const stagedDiff = await runLocalGit(input.localDir, ["diff", "--cached", "--name-status", "HEAD", "--"], {
timeout: 10_000,
maxBuffer: 1024 * 1024,
});
if (stagedDiff.stdout.trim().length > 0) {
throw new Error(
`Workspace restore left staged git index changes after reset:\n${stagedDiff.stdout.trim()}`,
);
}
if (!input.checkWorkingTreeClean) return;
const workingTreeDiff = await runLocalGit(input.localDir, ["diff", "--name-status", "HEAD", "--"], {
timeout: 10_000,
maxBuffer: 1024 * 1024,
});
if (workingTreeDiff.stdout.trim().length > 0) {
console.warn(
"[paperclip] Workspace restore preserved local working tree changes after clean sandbox restore.",
);
}
}
View on GitHub (pinned to 120ae5428f)
Solutions
- Inspect what survived: run `git status --porcelain` and `git diff` in the workspace directory.
- If you need a pristine tree, commit or stash the local changes, or explicitly clean them (git checkout -- . / git clean).
- Treat the message as expected behavior when local edits existed before the restore — data was deliberately preserved.
Defensive patterns
Strategy: validation
Validate before calling
import { execSync } from "node:child_process";
const dirty = execSync("git status --porcelain", { cwd: workspaceDir, encoding: "utf8" });
if (dirty.trim().length > 0) {
// decide before restore: commit, stash, or accept that restore preserves these edits
} Type guard
const isCleanStatus = (porcelain: string): boolean => porcelain.trim().length === 0;
Prevention
- Commit or stash local edits before triggering a clean sandbox restore if you want determinism.
- Read the warning as informational: restore preserves local work by design.
- After restore, run `git status --porcelain` to enumerate exactly what was kept.
When it happens
Trigger: A workspace that had local uncommitted edits (hotfixes, generated files) goes through a clean sandbox restore; the index resets to HEAD but the modified files remain on disk, so `git diff HEAD` still reports them.
Common situations: Agent run restored from a sandbox while a developer had local edits in the same checkout; generated artifacts differing from HEAD; end-of-line or permission-only diffs.
Related errors
- Current checkout is the primary repo worktree. Pass --branch
- Could not read execution-target Git context
- codex_startup_trust_git_resolution_failed
- Managed GitHub connection is unavailable
AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18).
Data as JSON: /api/errors/584db90a459541f0.
Report an issue: GitHub.