can1357/oh-my-pi · error
Security scan contains duplicate finding ids
Error message
Security scan contains duplicate finding ids
What it means
parseSecurityScanBundle validates the structural contract of a scan bundle beyond the schema: finding ids must be unique. Duplicate ids make by-id lookups and diffing ambiguous, so parsing fails fast with this error. It runs for every bundle read from disk, imported from Codex/SARIF, or cached in the store.
Source
Thrown at packages/coding-agent/src/security/contracts/validation.ts:36
const result = securityScanSchema(value);
if (result instanceof type.errors) throw schemaError("Security scan", result);
return result as SecurityScan;
}
export function parseSecurityScanPlan(value: unknown): SecurityScanPlan {
const { securityScanPlanSchema } = getSecurityContractSchemas();
const result = securityScanPlanSchema(value);
if (result instanceof type.errors) throw schemaError("Security scan plan", result);
return result as SecurityScanPlan;
}
export function parseSecurityScanBundle(value: unknown): SecurityScanBundle {
const { securityScanBundleSchema } = getSecurityContractSchemas();
const result = securityScanBundleSchema(value);
if (result instanceof type.errors) throw schemaError("Security scan bundle", result);
const bundle = result as SecurityScanBundle;
const findingIds = new Set(bundle.findings.map(finding => finding.id));
if (findingIds.size !== bundle.findings.length) throw new Error("Security scan contains duplicate finding ids");
const referencedFindingIds = new Set(bundle.scan.findingIds);
if (referencedFindingIds.size !== bundle.scan.findingIds.length) {
throw new Error("Security scan manifest contains duplicate finding references");
}
for (const findingId of referencedFindingIds) {
if (!findingIds.has(findingId)) throw new Error(`Security scan references missing finding: ${findingId}`);
}
for (const findingId of findingIds) {
if (!referencedFindingIds.has(findingId))
throw new Error(`Security scan omits finding from manifest: ${findingId}`);
}
for (const finding of bundle.findings) {
if (finding.scanId !== bundle.scan.id) {
throw new Error(`Finding ${finding.id} belongs to ${finding.scanId}, expected ${bundle.scan.id}`);
}
const evidenceIds = new Set(finding.evidence.map(evidence => evidence.id));
if (evidenceIds.size !== finding.evidence.length) {
throw new Error(`Finding ${finding.id} contains duplicate evidence ids`);View on GitHub (pinned to 9690622007)
Solutions
- Regenerate the bundle from the scanner instead of hand-merging exports
- If merging intentionally, re-key ids to be unique (e.g. prefix with source scan id) and keep scan.findingIds consistent
- Validate before parse: JSON.parse the file and check new Set(ids).size === ids.length
- Re-export a single authoritative scan rather than concatenating multiple runs
Example fix
// before
const merged = { ...a, findings: [...a.findings, ...b.findings] };
parseSecurityScanBundle(merged); // throws: duplicate ids
// after
const findings = [...a.findings, ...b.findings.map(f => ({ ...f, id: `${b.scan.id}:${f.id}` }))];
parseSecurityScanBundle({ ...a, findings, scan: { ...a.scan, findingIds: findings.map(f => f.id) } }); Defensive patterns
Strategy: validation
Validate before calling
const raw = JSON.parse(text);
const ids = raw.findings.map((f: { id: string }) => f.id);
if (new Set(ids).size !== ids.length) throw new Error("Bundle has duplicate finding ids; regenerate it"); Try / catch
try {
bundle = parseSecurityScanBundle(value);
} catch (err) {
if (err instanceof Error && err.message === "Security scan contains duplicate finding ids") {
// dedupe/re-key ids or re-export the scan
} else throw err;
} Prevention
- Never concatenate findings arrays from multiple exports without re-keying ids
- Derive ids from the scanner, not placeholders
- Validate exported bundles before archiving them
- Test your bundle generator for id collisions
When it happens
Trigger: Loading a JSON bundle file whose findings array contains two entries with the same id; importing a SARIF or Codex bundle whose conversion produced colliding ids.
Common situations: Manually merging two scan exports by concatenating findings arrays; a generator bug reusing placeholder ids; SARIF results from multiple runs merged without re-keying ids.
Related errors
- lookbackDays must be a positive integer or 'all'
- Security scan manifest contains duplicate finding references
- Finding ${finding.id} belongs to ${finding.scanId}, expected
- Finding ${finding.id} contains duplicate evidence ids
- Finding ${finding.id} contains duplicate occurrence ids
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ed4da0cd0b340b18.
Report an issue: GitHub.