can1357/oh-my-pi · error · Error

Invalid security scan id: ${scanId}

Error message

Invalid security scan id: ${scanId}

What it means

SecurityStore.#scanDirectory guards against path traversal and malformed ids by requiring scan ids to match /^secscan_[a-zA-Z0-9]+$/. Any other string is rejected before it is used to build the scans/<id> filesystem path, so untrusted ids cannot escape the store directory.

Source

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

		options.signal?.throwIfAborted();
		const repositoryRoot = vcs.repo(resolvedCwd)?.root() ?? resolvedCwd;
		return SecurityStore.open(repositoryRoot, options);
	}

	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({

View on GitHub (pinned to 9690622007)

Solutions

  1. Use the exact scan id returned by the store when the scan was created (e.g. secscan_abc123)
  2. Strip any decorations (quotes, ellipses, path prefixes) from a copy-pasted id
  3. Regenerate the scan if the id came from an old/incompatible store
  4. Validate ids against /^secscan_[a-zA-Z0-9]+$/ at your boundary before calling the store

Example fix

// before
store.getScan("my-scan-1");
// after
const { scanId } = await store.putScan(plan, findings); // "secscan_1a2b..."
store.getScan(scanId);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: getScan/rawFindings/report/sarifText/scanDirectory called with an id that lacks the 'secscan_' prefix, contains '/', '..', spaces, hyphens, or is empty — typically an id from user/LLM input or an older store.

Common situations: Storing and passing back a bare fingerprint instead of the scan id, truncating an id in UI/log copy-paste, hand-writing 'sec-scan_123', or legacy ids from a previous schema version.

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/79955aea9085dfe9. Report an issue: GitHub.