can1357/oh-my-pi · error

ref_diff security plan is missing resolved revisions

Error message

ref_diff security plan is missing resolved revisions

What it means

prepareSecurityExecutionTarget only handles ref_diff plans whose target carries fully resolved headRevision and baseRevision git refs; these are set during plan creation by resolving the diff range. If either is empty at execution time the plan is malformed or was produced by an older/newer plan format, so the coordinator refuses to build the worktree and diff.

Source

Thrown at packages/coding-agent/src/security/coordinator.ts:341

		return await repo.worktreeRemove(cwd, true);
	} catch {
		return false;
	}
}

async function prepareSecurityExecutionTarget(
	plan: SecurityScanPlan,
	store: SecurityStore,
	scanId: string,
	adapter: SecurityGitAdapter,
	signal: AbortSignal,
): Promise<PreparedSecurityExecutionTarget> {
	if (plan.target.kind !== "ref_diff") {
		return { cwd: plan.repositoryRoot, cleanup: async () => undefined };
	}
	const headRevision = plan.target.headRevision;
	const baseRevision = plan.target.baseRevision;
	if (!headRevision || !baseRevision) throw new Error("ref_diff security plan is missing resolved revisions");
	const targetsRoot = path.join(store.projectDirectory, "targets");
	await fs.mkdir(targetsRoot, { recursive: true, mode: 0o700 });
	if (process.platform !== "win32") await fs.chmod(targetsRoot, 0o700);
	const cwd = path.join(targetsRoot, scanId);
	const repo = vcs.requireGit(plan.repositoryRoot);
	let added = false;
	try {
		await repo.worktreeAdd(cwd, headRevision, true, signal);
		added = true;
		const diffText = await adapter.diffTree(plan.repositoryRoot, baseRevision, headRevision, signal);
		return {
			cwd,
			diffText,
			async cleanup() {
				const removed = await tryRemoveWorktree(repo, cwd);
				if (!removed) await fs.rm(cwd, { recursive: true, force: true });
			},
		};

View on GitHub (pinned to 9690622007)

Solutions

  1. Create a fresh plan via coordinator.preflight() so revisions are resolved against the current repository state, then start from that plan id.
  2. Verify the repository has valid HEAD and base refs (git rev-parse HEAD and the base revision) before scanning a ref_diff target.
  3. Delete stale persisted plans and regenerate; check for a version mismatch if plans came from an older release.
  4. If constructing plans in code, use createSecurityScanPlan rather than building the target object manually.

Example fix

// before
const plan = await store.getPlan(oldPlanId); // pre-resolution plan
await coordinator.start({ planId: oldPlanId });
// after
const plan = await coordinator.preflight({ target: { kind: "ref_diff", baseRevision: "main" } });
await coordinator.start({ planId: plan.id });
Defensive patterns

Strategy: validation

Validate before calling

if (plan.target.kind === "ref_diff") {
  const { headRevision, baseRevision } = plan.target;
  if (!headRevision || !baseRevision) throw new Error("ref_diff target missing revisions; re-plan");
}

Type guard

function hasResolvedRevisions(target: SecurityScanPlan["target"]): target is Extract<typeof target, { kind: "ref_diff"; headRevision: string; baseRevision: string }> {
  return target.kind !== "ref_diff" || (Boolean(target.headRevision) && Boolean(target.baseRevision));
}

Try / catch

try {
  await coordinator.start({ planId });
} catch (err) {
  if (err instanceof Error && err.message === "ref_diff security plan is missing resolved revisions") {
    const plan = await coordinator.preflight({ target: desiredTarget });
    await coordinator.start({ planId: plan.id });
  } else throw err;
}

Prevention

When it happens

Trigger: Calling coordinator.start() with a ref_diff plan whose target.headRevision or target.baseRevision is empty/undefined — e.g. a plan loaded from a store written before revisions were resolved, a plan created while HEAD/base could not be resolved, or a hand-constructed SecurityScanPlan passed directly to #run paths.

Common situations: Running a scan against a repository with no commits or an unborn HEAD; plan persisted by a different version of the tool with an incompatible plan schema; constructing a plan programmatically without going through preflight/createSecurityScanPlan.

Related errors


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