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
- Use the exact scan id returned by the store when the scan was created (e.g. secscan_abc123)
- Strip any decorations (quotes, ellipses, path prefixes) from a copy-pasted id
- Regenerate the scan if the id came from an old/incompatible store
- 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
- Treat ids as opaque strings from API responses
- Validate format at boundaries
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
- Invalid security plan id: ${planId}
- Destination paths cannot contain parent traversal or NUL byt
- Shared-folder destination escapes its configured root
- Absolute paths are not allowed in ${scheme}:// URLs: ${rawPa
- Path traversal (..) is not allowed in ${scheme}:// URLs: ${r
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/79955aea9085dfe9.
Report an issue: GitHub.