{"record":{"id":"25c8b92663239943","repo":"can1357/oh-my-pi","slug":"finding-finding-id-contains-duplicate-evidence","errorCode":null,"errorMessage":"Finding ${finding.id} contains duplicate evidence ids","messagePattern":"Finding (.+?) contains duplicate evidence ids","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/contracts/validation.ts","lineNumber":54,"sourceCode":"\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) {\n\t\t\tfor (const evidenceId of occurrence.evidenceIds) {\n\t\t\t\tif (!evidenceIds.has(evidenceId)) {\n\t\t\t\t\tthrow new Error(`Occurrence ${occurrence.id} references missing evidence: ${evidenceId}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn bundle;\n}\n","sourceCodeStart":36,"sourceCodeEnd":70,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/contracts/validation.ts#L36-L70","documentation":"parseSecurityScanBundle checks that every finding's evidence entries have unique ids by comparing Set size to array length. Duplicate evidence ids within one finding indicate malformed evidence collection — deduplication must happen at production time because consumers key on evidence.id.","triggerScenarios":"Calling bundle()/readBundle()/importSarif()/importCodexSecurityBundle() on a bundle where a finding's evidence array contains two entries with the same id — typically from an importer appending the same evidence twice or a generator bug.","commonSituations":"SARIF imports where a result maps to the same code location multiple times and the import code assigns the same evidence id each time; retries during scan generation that re-append evidence without clearing the array.","solutions":["Deduplicate the evidence array by id in the bundle JSON before loading.","Fix the importer/generator so evidence ids are unique (e.g. derive from result index or a stable hash of the evidence content).","Re-run the scan to regenerate a clean bundle if the source store is corrupted."],"exampleFix":"// before\nfinding.evidence = [...oldEvidence, ...newEvidence]; // overlapping entries\n// after\nconst merged = new Map(finding.evidence.map(e => [e.id, e]));\nfinding.evidence = [...merged.values()];","handlingStrategy":"validation","validationCode":"for (const f of bundle.findings) {\n  const ids = f.evidence.map(e => e.id);\n  if (new Set(ids).size !== ids.length) throw new Error(`duplicate evidence ids in finding ${f.id}`);\n}","typeGuard":"function hasUniqueEvidenceIds(finding: SecurityFinding): boolean {\n  const ids = finding.evidence.map(e => e.id);\n  return new Set(ids).size === ids.length;\n}","tryCatchPattern":"try {\n  const bundle = readBundle(scanId);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"duplicate evidence ids\")) {\n    // regenerate or deduplicate the bundle before retrying\n  } else throw err;\n}","preventionTips":["Build evidence arrays through Map/id-keyed insertion so duplicates collapse automatically.","Make evidence ids deterministic (hash of content or location) rather than sequence-based.","Validate bundles after any import transform, before persisting."],"tags":["validation","duplicate-ids","security-scan"],"backgroundTag":"duplicate-identifier","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}