can1357/oh-my-pi · error
Unknown security scan plan: ${input.planId}
Error message
Unknown security scan plan: ${input.planId} What it means
start() looks up the plan by id in the security store for the current working directory. If store.getPlan(planId) returns null the plan doesn't exist (or isn't in this store), so the coordinator throws with the offending id. Plans are persisted by preflight() into a project-scoped store.
Source
Thrown at packages/coding-agent/src/security/coordinator.ts:467
account,
config: securityConfigSnapshot(this.#host.settings),
workflowFingerprint: SECURITY_WORKFLOW_FINGERPRINT,
signal: input.signal,
},
this.#gitAdapter,
);
await store.putPlan(plan);
return plan;
}
async start(input: SecurityStartInput): Promise<SecurityOperationSnapshot> {
if (!this.#host.settings.get("security.enabled")) {
throw new Error("Security is disabled; enable security.enabled before starting a scan");
}
await this.#ensureRecovered();
const store = await this.#openStore(this.#host.cwd);
const plan = await store.getPlan(input.planId);
if (!plan) throw new Error(`Unknown security scan plan: ${input.planId}`);
await assertSecurityScanPlanFresh(
plan,
{
config: securityConfigSnapshot(this.#host.settings),
workflowFingerprint: SECURITY_WORKFLOW_FINGERPRINT,
},
this.#gitAdapter,
);
const operationId = this.#createOperationId();
const scanId = createSecurityScanId();
const createdAt = toIsoTimestamp(this.#now);
const snapshot: SecurityOperationSnapshot = {
operationId,
planId: plan.id,
scanId,
phase: "queued",
createdAt,
updatedAt: createdAt,View on GitHub (pinned to 9690622007)
Solutions
- Run coordinator.preflight() again to create a fresh plan, and use the returned plan.id for start().
- Confirm the plan id exists in the store for the exact cwd passed to the coordinator — match the working directory used at preflight time.
- Check for stale/expired plans: plans go through assertSecurityScanPlanFresh after lookup, so regenerate rather than reusing old ids.
- Verify you didn't truncate or clean the security store directory between planning and start.
Example fix
// before
await coordinator.start({ planId: rememberedPlanId }); // may be gone
// after
const plan = await coordinator.preflight();
await coordinator.start({ planId: plan.id }); Defensive patterns
Strategy: validation
Validate before calling
const store = await SecurityStore.openForCwd(coordinatorCwd);
if (!(await store.getPlan(planId))) throw new Error(`plan ${planId} not found in store for ${coordinatorCwd}`); Try / catch
try {
await coordinator.start({ planId });
} catch (err) {
if (err instanceof Error && err.message.startsWith("Unknown security scan plan")) {
const plan = await coordinator.preflight();
await coordinator.start({ planId: plan.id });
} else throw err;
} Prevention
- Always chain preflight → start with the plan object returned by preflight, never a remembered id.
- Keep cwd consistent between planning and starting; the store is project-scoped.
- Don't reuse plan ids across sessions, machines, or after store cleanup.
When it happens
Trigger: Calling start() with a planId that was never created, already consumed/deleted, or created by a preflight in a different repository/cwd so a different store is opened; typos in a plan id copied from logs.
Common situations: Re-running automation against an expired or pruned plan store; switching project directories between preflight and start; using a plan id from another machine or session.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- directory stack is empty
- No messages to continue from
- Cannot continue from message role: assistant
- Cursor blob not found
- Not a git repository
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/5347250fceb71a4a.
Report an issue: GitHub.