can1357/oh-my-pi · error · Error

Invalid security plan id: ${planId}

Error message

Invalid security plan id: ${planId}

What it means

SecurityStore.#planPath enforces that plan ids match /^secplan_[a-zA-Z0-9]+$/ before using them in the plans/<id>.json path. This rejects malformed ids and prevents traversal out of the store's plans directory.

Source

Thrown at packages/coding-agent/src/security/store.ts:195

	get repositoryRoot(): string {
		return this.#repositoryRoot;
	}

	get projectKey(): string {
		return this.#projectKey;
	}

	get projectDirectory(): string {
		return this.#projectDirectory;
	}

	#scanDirectory(scanId: string): string {
		if (!/^secscan_[a-zA-Z0-9]+$/.test(scanId)) throw new Error(`Invalid security scan id: ${scanId}`);
		return path.join(this.#projectDirectory, "scans", scanId);
	}

	#planPath(planId: string): string {
		if (!/^secplan_[a-zA-Z0-9]+$/.test(planId)) throw new Error(`Invalid security plan id: ${planId}`);
		return path.join(this.#projectDirectory, "plans", `${planId}.json`);
	}

	#indexPath(): string {
		return path.join(this.#projectDirectory, "index.json");
	}

	async #ensureIndex(): Promise<void> {
		try {
			await this.#readIndex();
		} catch (error) {
			if (!isEnoent(error)) throw error;
			await this.#writeIndex({
				schemaVersion: STORE_SCHEMA_VERSION,
				projectKey: this.#projectKey,
				repositoryRoot: this.#repositoryRoot,
				scanIds: [],
				planIds: [],

View on GitHub (pinned to 9690622007)

Solutions

  1. Use the plan id generated by putPlan (secplan_ prefixed) rather than a custom one
  2. Check you are not passing a scan id (secscan_...) to getPlan
  3. Sanitize/validate the id with /^secplan_[a-zA-Z0-9]+$/ before calling the store
  4. Recreate the plan if the original id is lost

Example fix

// before
store.getPlan("plan-001");
// after
const { planId } = await store.putPlan(plan); // "secplan_x9y8..."
store.getPlan(planId);
Defensive patterns

Strategy: validation

Validate before calling

if (!/^secplan_[a-zA-Z0-9]+$/.test(planId)) throw new Error("bad plan id");

Type guard

function isPlanId(v: unknown): v is string { return typeof v === "string" && /^secplan_[a-zA-Z0-9]+$/.test(v); }

Try / catch

try { store.getPlan(planId); } catch (e) { if (String(e.message).startsWith("Invalid security plan id")) { /* re-fetch id */ } else throw e; }

Prevention

When it happens

Trigger: putPlan/getPlan called with an id missing the 'secplan_' prefix or containing illegal characters (slashes, dots, hyphens, whitespace), usually an id produced outside the store.

Common situations: Hand-rolled plan ids like 'plan-001', ids remembered from a previous schema, passing a scan id where a plan id is expected, or truncated ids from logs.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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