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

  1. Commit the pending changes with `git commit -am "wip"` before creating the remediation workspace
  2. Stash them with `git stash -u` (including untracked files), run remediation, then `git stash pop`
  3. Clean untracked artifacts with `git clean -n` (review) then `git clean -fd` if safe
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/cc85e78d3dd39284. Report an issue: GitHub.