{"record":{"id":"9ca49219d4ecb80e","repo":"can1357/oh-my-pi","slug":"invalid-security-store-scan-index-at-this-index","errorCode":null,"errorMessage":"Invalid security store scan index at ${this.#indexPath()}","messagePattern":"Invalid security store scan index at (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/store.ts","lineNumber":225,"sourceCode":"\t\t\tif (!isEnoent(error)) throw error;\n\t\t\tawait this.#writeIndex({\n\t\t\t\tschemaVersion: STORE_SCHEMA_VERSION,\n\t\t\t\tprojectKey: this.#projectKey,\n\t\t\t\trepositoryRoot: this.#repositoryRoot,\n\t\t\t\tscanIds: [],\n\t\t\t\tplanIds: [],\n\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t});\n\t\t}\n\t}\n\n\tasync #readIndex(): Promise<SecurityStoreIndex> {\n\t\tconst value = (await readJsonFile(this.#indexPath())) as Partial<SecurityStoreIndex>;\n\t\tif (value.schemaVersion !== STORE_SCHEMA_VERSION || value.projectKey !== this.#projectKey) {\n\t\t\tthrow new Error(`Unsupported security store index at ${this.#indexPath()}`);\n\t\t}\n\t\tif (!Array.isArray(value.scanIds) || !value.scanIds.every(id => typeof id === \"string\")) {\n\t\t\tthrow new Error(`Invalid security store scan index at ${this.#indexPath()}`);\n\t\t}\n\t\tif (\n\t\t\tvalue.planIds !== undefined &&\n\t\t\t(!Array.isArray(value.planIds) || !value.planIds.every(id => typeof id === \"string\"))\n\t\t) {\n\t\t\tthrow new Error(`Invalid security store plan index at ${this.#indexPath()}`);\n\t\t}\n\t\treturn { ...value, planIds: value.planIds ?? [] } as SecurityStoreIndex;\n\t}\n\n\tasync #writeIndex(index: SecurityStoreIndex): Promise<void> {\n\t\tawait writeSecurityFileAtomic(this.#indexPath(), `${JSON.stringify(index, null, 2)}\\n`);\n\t}\n\n\tasync #putBundleUnlocked(input: SecurityScanBundle): Promise<void> {\n\t\tconst bundle = parseSecurityScanBundle(input);\n\t\tif (bundle.scan.projectKey !== this.#projectKey) {\n\t\t\tthrow new Error(`Security scan project key ${bundle.scan.projectKey} does not match ${this.#projectKey}`);","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/store.ts#L207-L243","documentation":"#readIndex additionally validates the shape of the index: scanIds must be an array of strings (and planIds, when present, likewise). If the JSON parses but its scanIds field is missing or of the wrong type, the index is considered corrupt and the store throws instead of operating on an unusable index.","triggerScenarios":"Reading index.json where scanIds is undefined/null/an object or contains non-string entries — typically from manual edits, a partial write/crash, or corruption; note the schemaVersion/projectKey check already passed.","commonSituations":"Hand-edited index files, concurrent writes without locking, disk-full truncation producing valid JSON with wrong fields, or copying an index between projects that kept one project's arrays.","solutions":["Delete or restore a valid scans/index.json so #ensureIndex rebuilds it","Recreate the index by re-running scans, or restore from backup/version control if tracked","Fix scanIds to be an array of secscan_ id strings if you are intentionally hand-repairing","Investigate what corrupted the file (concurrent writers, disk issues) before re-running"],"exampleFix":"// before\n// index.json: { schemaVersion: 2, projectKey: \"k\", scanIds: null }\n// after\n// index.json: { schemaVersion: 2, projectKey: \"k\", scanIds: [\"secscan_1a2b\"] }","handlingStrategy":"try-catch","validationCode":"const idx = await Bun.file(indexPath).json();\nif (!Array.isArray(idx.scanIds)) console.warn(\"scan index corrupt\");","typeGuard":"null","tryCatchPattern":"try { openStore(dir); } catch (e) { if (String(e.message).startsWith(\"Invalid security store scan index\")) { await fs.rm(indexPath); } else throw e; }","preventionTips":["Single writer per store","Never hand-edit index.json"],"tags":["persistence","corruption","validation"],"backgroundTag":"store-index-corrupt","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}