can1357/oh-my-pi · error · Error

Unknown security scan: ${scanId}

Error message

Unknown security scan: ${scanId}

What it means

updateDisposition() loads the full scan bundle; #getBundleUnlocked returns null when scans/<scanId>/scan.json does not exist (or the scan id fails the secscan_ format check). The method then throws this error because a disposition can only be recorded on an existing scan.

Source

Thrown at packages/coding-agent/src/security/store.ts:368

				target: bundle.scan.target,
			});
		}
		return summaries;
	}

	async getFinding(scanId: string, findingId: string): Promise<SecurityFinding | null> {
		const bundle = await this.getBundle(scanId);
		return bundle?.findings.find(finding => finding.id === findingId) ?? null;
	}

	async updateDisposition(
		scanId: string,
		findingId: string,
		disposition: SecurityDisposition,
	): Promise<SecurityFinding> {
		return withSecurityStoreWrite(this.#projectDirectory, async () => {
			const bundle = await this.#getBundleUnlocked(scanId);
			if (!bundle) throw new Error(`Unknown security scan: ${scanId}`);
			const index = bundle.findings.findIndex(finding => finding.id === findingId);
			if (index < 0) throw new Error(`Unknown security finding: ${findingId}`);
			const canonicalDisposition: SecurityDisposition = { status: disposition.status };
			if (disposition.rationale !== undefined) canonicalDisposition.rationale = disposition.rationale;
			if (disposition.updatedAt !== undefined) canonicalDisposition.updatedAt = disposition.updatedAt;
			if (disposition.actor !== undefined) canonicalDisposition.actor = disposition.actor;
			const updated = { ...bundle.findings[index], disposition: canonicalDisposition };
			bundle.findings[index] = parseSecurityFinding(updated);
			if (bundle.sarif !== undefined) bundle.sarif = exportSecurityBundleToSarif(bundle);
			await this.#putBundleUnlocked(bundle);
			return bundle.findings[index];
		});
	}

	async updateValidation(
		scanId: string,
		findingId: string,
		validation: SecurityValidation,

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the scan exists with await store.getScan(scanId) or store.listScans() and use a valid id before updating.
  2. Confirm you opened the same store (same repositoryRoot/stateRoot) that wrote the scan — project directories are keyed per repo.
  3. Check index.json scanIds to see whether the id was ever registered in this store.
  4. If the scan directory was deleted, re-run the scan and putBundle() before attempting updates.

Example fix

// before
await store.updateDisposition('secscan_9x', findingId, disposition); // typo'd id
// after
const scan = await store.getScan('secscan_9x');
if (scan) await store.updateDisposition(scan.id, findingId, disposition);
Defensive patterns

Strategy: type-guard

Validate before calling

const scan = await store.getScan(scanId);
if (!scan) throw new Error(`scan ${scanId} not found in ${store.projectDirectory}`);

Type guard

function isKnownScan(s: SecurityScan | null): s is SecurityScan {
  return s !== null;
}

Try / catch

try {
  await store.updateDisposition(scanId, findingId, disposition);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Unknown security scan')) {
    const scans = await store.listScans();
    console.error(`scan ${scanId} not found; known: ${scans.map(s => s.id).join(', ')}`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling updateDisposition(scanId, findingId, disposition) with a scanId that has no stored scan.json — typo'd id, scan deleted from disk, wrong store (different repositoryRoot/stateRoot so a different project directory), or a malformed id not matching /^secscan_[a-zA-Z0-9]+$/.

Common situations: Storing scan ids from logs with surrounding whitespace/quotes; referencing a scan from a different repo's store after a checkout switch; the scans/<id>/ directory partially removed while index.json still lists it; case/character mistakes when copying ids.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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