can1357/oh-my-pi · error

Security comparison produced an invalid finding reference

Error message

Security comparison produced an invalid finding reference

What it means

compareSecurityLineage maps the producer-differential's matches back to actual finding objects by id. If a match references a finding id absent from either bundle's findings array, the differential produced an internally inconsistent pairing; the function throws instead of emitting a match with dangling references.

Source

Thrown at packages/coding-agent/src/security/comparison.ts:227

export function compareSecurityLineage(
	before: SecurityScanBundle,
	after: SecurityScanBundle,
): SecurityComparisonReport {
	// An incomplete after-scan proves nothing about unmatched earlier findings;
	// claiming them "resolved" against a cancelled/partial/failed run would be a lie.
	if (after.scan.status !== "completed") {
		throw new Error(
			`Security lineage comparison requires a completed after-scan; ${after.scan.id} is ${after.scan.status}`,
		);
	}
	const differential = compareSecurityProducers(before, after);
	const beforeById = new Map(before.findings.map(finding => [finding.id, finding]));
	const afterById = new Map(after.findings.map(finding => [finding.id, finding]));
	const matches: SecurityFindingMatch[] = differential.matches.map(match => {
		const beforeFinding = beforeById.get(match.referenceFindingId);
		const afterFinding = afterById.get(match.candidateFindingId);
		if (!beforeFinding || !afterFinding) throw new Error("Security comparison produced an invalid finding reference");
		return {
			beforeFindingId: beforeFinding.id,
			afterFindingId: afterFinding.id,
			fingerprint: beforeFinding.fingerprint,
			status: "unchanged",
			matchBasis: match.basis,
		};
	});
	for (const findingId of differential.referenceOnlyFindingIds) {
		const finding = beforeById.get(findingId);
		if (!finding) continue;
		matches.push({ beforeFindingId: finding.id, fingerprint: finding.fingerprint, status: "resolved" });
	}
	for (const findingId of differential.candidateOnlyFindingIds) {
		const finding = afterById.get(findingId);
		if (!finding) continue;
		matches.push({ afterFindingId: finding.id, fingerprint: finding.fingerprint, status: "new" });
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass the complete, unmodified bundles (as produced by readBundle/parseSecurityScanBundle) to compareSecurityLineage
  2. Regenerate the comparison from freshly read bundles instead of reusing partial in-memory copies
  3. Verify finding ids were not rewritten between the two scans (fingerprints should be stable)
  4. If reproducible with intact bundles, report the upstream differential bug

Example fix

// before
const filtered = { ...after, findings: after.findings.filter(f => f.severity === "high") };
const report = compareSecurityLineage(before, filtered);
// after
const report = compareSecurityLineage(before, after); // compare full bundles, filter the report
Defensive patterns

Strategy: validation

Validate before calling

const bIds = new Set(before.findings.map(f => f.id));
const aIds = new Set(after.findings.map(f => f.id));
if (before.scan.findingIds.some(id => !bIds.has(id)) || after.scan.findingIds.some(id => !aIds.has(id))) {
	throw new Error("Bundle inconsistent; re-read bundles before comparing");
}

Try / catch

try {
	report = compareSecurityLineage(before, after);
} catch (err) {
	if (err instanceof Error && err.message === "Security comparison produced an invalid finding reference") {
		// reload bundles from disk and retry the comparison once
	} else throw err;
}

Prevention

When it happens

Trigger: A before/after bundle pair where compareSecurityProducers returns a match whose referenceFindingId or candidateFindingId is not present in the respective bundle's findings list — e.g. hand-assembled or partially filtered bundles passed as before/after.

Common situations: Building bundles programmatically and filtering findings without updating the differential inputs; external tooling rewriting finding ids between scans (breaking fingerprint/id pairing); a bug or version skew between the producer that generated matches and the bundle serializer.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/d218baa66473d405. Report an issue: GitHub.