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

  1. Run coordinator.preflight() again to create a fresh plan, and use the returned plan.id for start().
  2. Confirm the plan id exists in the store for the exact cwd passed to the coordinator — match the working directory used at preflight time.
  3. Check for stale/expired plans: plans go through assertSecurityScanPlanFresh after lookup, so regenerate rather than reusing old ids.
  4. 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

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


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