can1357/oh-my-pi · error · Error
Security remediation refuses a dirty working tree (${dirty.j
Error message
Security remediation refuses a dirty working tree (${dirty.join(", ")}). Commit or stash the changes before creating an isolated remediation workspace. What it means
assertSecurityRemediationBaselineClean inspects the WorktreeBaseline of the project and refuses to create an isolated remediation worktree when the working tree has uncommitted changes. Remediation needs a pristine baseline so generated fixes can be isolated and reviewed as a clean diff.
Source
Thrown at packages/coding-agent/src/security/remediation.ts:57
if (baseline.root.unstaged.trim()) dirty.push("unstaged changes");
if (baseline.root.untracked.length > 0 || baseline.root.untrackedPatch.trim()) dirty.push("untracked files");
for (const nested of baseline.nested) {
if (
nested.baseline.staged.trim() ||
nested.baseline.unstaged.trim() ||
nested.baseline.untracked.length > 0 ||
nested.baseline.untrackedPatch.trim()
) {
dirty.push(`dirty nested repository ${nested.relativePath}`);
}
}
return dirty;
}
export function assertSecurityRemediationBaselineClean(baseline: WorktreeBaseline): void {
const dirty = repoBaselineDirty(baseline);
if (dirty.length === 0) return;
throw new Error(
[
`Security remediation refuses a dirty working tree (${dirty.join(", ")}).`,
"Commit or stash the changes before creating an isolated remediation workspace.",
].join(" "),
);
}
export async function prepareSecurityRemediationWorkspace(
request: SecurityRemediationRequest,
dependencies: SecurityRemediationDependencies = {},
): Promise<SecurityRemediationWorkspace> {
const findingIds = [...new Set(request.findingIds.map(id => id.trim()).filter(Boolean))];
if (findingIds.length === 0) throw new Error("Security remediation requires at least one finding id");
const prepareContext = dependencies.prepareContext ?? prepareIsolationContext;
const createIsolation = dependencies.createIsolation ?? ensureIsolation;
const disposeIsolation = dependencies.cleanupIsolation ?? cleanupIsolation;
const context = await prepareContext(request.cwd);
assertSecurityRemediationBaselineClean(context.baseline);View on GitHub (pinned to 9690622007)
Solutions
- Commit the pending changes with `git commit -am "wip"` before creating the remediation workspace
- Stash them with `git stash -u` (including untracked files), run remediation, then `git stash pop`
- Clean untracked artifacts with `git clean -n` (review) then `git clean -fd` if safe
- Check `git status --porcelain` first to see exactly which paths are dirty
Example fix
// before
await prepareSecurityRemediationWorkspace({ cwd, findingIds });
// after
await $`git -C ${cwd} stash -u`;
await prepareSecurityRemediationWorkspace({ cwd, findingIds });
await $`git -C ${cwd} stash pop`; Defensive patterns
Strategy: validation
Validate before calling
if ((await $`git -C ${cwd} status --porcelain`.text()).trim()) throw new Error("dirty tree"); Type guard
null
Try / catch
try { await prepare(request); } catch (e) { if (String(e.message).includes("dirty working tree")) { await $`git stash -u`; } else throw e; } Prevention
- Require clean `git status --porcelain` preflight
- Stash with -u to include untracked files
When it happens
Trigger: Calling prepareSecurityRemediationWorkspace (directly or via the workspace command) while `git status` shows modified, staged, untracked, or conflicting files in the repo.
Common situations: Developer had local edits/WIP in the repo when starting remediation, untracked build artifacts or config files, leftovers from a previous failed remediation, or a dirty checkout on CI.
Related errors
- No staged changes to analyze
- not a repository: {path}
- reference not found: {name}
- object not found: {spec}
- cherry-pick of {sha} is empty
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/cc85e78d3dd39284.
Report an issue: GitHub.