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
- Create a fresh plan via coordinator.preflight() so revisions are resolved against the current repository state, then start from that plan id.
- Verify the repository has valid HEAD and base refs (git rev-parse HEAD and the base revision) before scanning a ref_diff target.
- Delete stale persisted plans and regenerate; check for a version mismatch if plans came from an older release.
- 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
- Always create ref_diff plans through preflight()/createSecurityScanPlan so revisions get resolved.
- Re-plan after pulling/branching so resolved refs still exist.
- Treat persisted plans as ephemeral: create, start, and discard within one run.
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
- ref_diff preflight requires base_revision and head_revision
- 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/b92efc068401cf44.
Report an issue: GitHub.