can1357/oh-my-pi · error

Finding ${finding.id} belongs to ${finding.scanId}, expected

Error message

Finding ${finding.id} belongs to ${finding.scanId}, expected ${bundle.scan.id}

What it means

parseSecurityScanBundle validates referential integrity of a security scan bundle after schema validation. Every finding in bundle.findings must declare the same scanId as the bundle's scan record; a mismatch means the findings array and the scan manifest describe different scans. The library throws to prevent mixing findings across scans when loading, importing (Sarif/Codex), or reading bundles from disk.

Source

Thrown at packages/coding-agent/src/security/contracts/validation.ts:50

	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`);
		}
		const occurrenceIds = new Set(finding.occurrences.map(occurrence => occurrence.id));
		if (occurrenceIds.size !== finding.occurrences.length) {
			throw new Error(`Finding ${finding.id} contains duplicate occurrence ids`);
		}
		for (const occurrence of finding.occurrences) {
			for (const evidenceId of occurrence.evidenceIds) {
				if (!evidenceIds.has(evidenceId)) {
					throw new Error(`Occurrence ${occurrence.id} references missing evidence: ${evidenceId}`);
				}
			}
		}
	}
	return bundle;

View on GitHub (pinned to 9690622007)

Solutions

  1. Open the bundle JSON and compare each finding's scanId with scan.id; make them consistent (usually the finding's scanId is stale — update it to match bundle.scan.id).
  2. Regenerate the bundle from the original scan run instead of hand-editing it.
  3. If merging scans, merge at the scan level: keep each finding with its own scan record rather than cross-assigning findings.
  4. Check the importer (Sarif/Codex) invocation — ensure the source file corresponds to a single scan and wasn't corrupted in transit.

Example fix

// before (hand-edited bundle.json)
{ "scan": { "id": "scan-2" }, "findings": [{ "id": "f1", "scanId": "scan-1" }] }
// after
{ "scan": { "id": "scan-2" }, "findings": [{ "id": "f1", "scanId": "scan-2" }] }
Defensive patterns

Strategy: validation

Validate before calling

const mismatched = bundle.findings.filter(f => f.scanId !== bundle.scan.id);
if (mismatched.length) throw new Error(`findings with foreign scanId: ${mismatched.map(f => f.id).join(", ")}`);

Type guard

function hasConsistentScanIds(bundle: SecurityScanBundle): boolean {
  return bundle.findings.every(f => f.scanId === bundle.scan.id);
}

Try / catch

try {
  const bundle = parseSecurityScanBundle(raw);
  // use bundle
} catch (err) {
  if (err instanceof Error && err.message.includes("belongs to")) {
    logger.warn("bundle contains findings from another scan", { cause: err.message });
  } else throw err;
}

Prevention

When it happens

Trigger: Calling bundle(), readBundle(), importSarif(), or importCodexSecurityBundle() with a bundle JSON where one or more findings have scanId different from bundle.scan.id — e.g. hand-merged scan files, a copied scan record paired with another scan's findings, or an importer that misassigns scanId.

Common situations: Manually editing or concatenating scan output files under the security store; post-processing scripts that rewrite scan.id but not finding.scanId; importing SARIF produced by external tooling where run-to-finding linkage was reconstructed incorrectly.

Related errors


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