{"record":{"id":"c1b37c7442b10ee0","repo":"can1357/oh-my-pi","slug":"security-scan-references-missing-finding-findin","errorCode":null,"errorMessage":"Security scan references missing finding: ${findingId}","messagePattern":"Security scan references missing finding: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/contracts/validation.ts","lineNumber":42,"sourceCode":"\tconst { securityScanPlanSchema } = getSecurityContractSchemas();\n\tconst result = securityScanPlanSchema(value);\n\tif (result instanceof type.errors) throw schemaError(\"Security scan plan\", result);\n\treturn result as SecurityScanPlan;\n}\n\nexport function parseSecurityScanBundle(value: unknown): SecurityScanBundle {\n\tconst { securityScanBundleSchema } = getSecurityContractSchemas();\n\tconst result = securityScanBundleSchema(value);\n\tif (result instanceof type.errors) throw schemaError(\"Security scan bundle\", result);\n\tconst bundle = result as SecurityScanBundle;\n\tconst findingIds = new Set(bundle.findings.map(finding => finding.id));\n\tif (findingIds.size !== bundle.findings.length) throw new Error(\"Security scan contains duplicate finding ids\");\n\tconst referencedFindingIds = new Set(bundle.scan.findingIds);\n\tif (referencedFindingIds.size !== bundle.scan.findingIds.length) {\n\t\tthrow new Error(\"Security scan manifest contains duplicate finding references\");\n\t}\n\tfor (const findingId of referencedFindingIds) {\n\t\tif (!findingIds.has(findingId)) throw new Error(`Security scan references missing finding: ${findingId}`);\n\t}\n\tfor (const findingId of findingIds) {\n\t\tif (!referencedFindingIds.has(findingId))\n\t\t\tthrow new Error(`Security scan omits finding from manifest: ${findingId}`);\n\t}\n\tfor (const finding of bundle.findings) {\n\t\tif (finding.scanId !== bundle.scan.id) {\n\t\t\tthrow new Error(`Finding ${finding.id} belongs to ${finding.scanId}, expected ${bundle.scan.id}`);\n\t\t}\n\t\tconst evidenceIds = new Set(finding.evidence.map(evidence => evidence.id));\n\t\tif (evidenceIds.size !== finding.evidence.length) {\n\t\t\tthrow new Error(`Finding ${finding.id} contains duplicate evidence ids`);\n\t\t}\n\t\tconst occurrenceIds = new Set(finding.occurrences.map(occurrence => occurrence.id));\n\t\tif (occurrenceIds.size !== finding.occurrences.length) {\n\t\t\tthrow new Error(`Finding ${finding.id} contains duplicate occurrence ids`);\n\t\t}\n\t\tfor (const occurrence of finding.occurrences) {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/contracts/validation.ts#L24-L60","documentation":"Every id listed in scan.findingIds must correspond to an actual finding in the findings array. If the manifest references a finding that does not exist, the bundle is internally inconsistent and parseSecurityScanBundle throws with the missing id.","triggerScenarios":"Parsing a bundle where scan.findingIds contains an id absent from bundle.findings — e.g. findings were filtered out but the manifest was left intact.","commonSituations":"Hand-editing an export to drop findings without updating the manifest; a partial/truncated export (findings array cut short); merging bundles and dropping findings while keeping one combined manifest.","solutions":["Rebuild the manifest from the findings array: scan.findingIds = findings.map(f => f.id)","Re-export the full scan without filtering the findings array","Validate pre-parse and strip unreferenced manifest entries","Regenerate the bundle from the scanner if the file was truncated"],"exampleFix":"// before\nparseSecurityScanBundle(raw); // manifest references id not in findings\n// after\nconst ids = new Set(raw.findings.map(f => f.id));\nraw.scan.findingIds = raw.scan.findingIds.filter(id => ids.has(id));\nparseSecurityScanBundle(raw);","handlingStrategy":"validation","validationCode":"const ids = new Set(raw.findings.map((f: { id: string }) => f.id));\nconst missing = raw.scan.findingIds.filter((id: string) => !ids.has(id));\nif (missing.length) throw new Error(`Manifest references missing findings: ${missing.join(\", \")}`);","typeGuard":null,"tryCatchPattern":"try {\n\tbundle = parseSecurityScanBundle(value);\n} catch (err) {\n\tif (err instanceof Error && err.message.startsWith(\"Security scan references missing finding:\")) {\n\t\traw.scan.findingIds = raw.scan.findingIds.filter(id => ids.has(id));\n\t\tbundle = parseSecurityScanBundle(raw);\n\t} else throw err;\n}","preventionTips":["Always regenerate the manifest whenever findings are filtered or removed","Check exports for truncation before parsing (file size, entry counts)","Treat hand-edited bundle JSON as suspect; re-export instead"],"tags":["validation","manifest","integrity"],"backgroundTag":"manifest-reference-missing","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}