can1357/oh-my-pi · error

Unknown security finding: ${findingId}

Error message

Unknown security finding: ${findingId}

What it means

When the URL targets a specific finding (security://scans/<id>/findings/<findingId>), resolve() calls store.getFinding(scanId, findingId); if no finding with that id exists in the scan bundle, it throws "Unknown security finding: <findingId>". The scan exists but the referenced finding id does not match any finding it contains.

Source

Thrown at packages/coding-agent/src/internal-urls/security-protocol.ts:195

			case "findings": {
				if (parts.length === 3) {
					const listing = bundle.findings.map(finding =>
						[
							`- \`${finding.id}\` **${finding.severity.level}** — ${sanitizeText(finding.title)}`,
							` (\`${sanitizeText(finding.ruleId)}\`)`,
						].join(""),
					);
					return createSecurityResource({
						url: `security://scans/${scanId}/findings`,
						content: `# Findings for ${scanId}\n\n${listing.length > 0 ? listing.join("\n") : "No findings."}\n`,
						contentType: "text/markdown",
						isDirectory: true,
					});
				}
				if (parts.length !== 4) throw new Error(`Unknown security resource: security://${parts.join("/")}`);
				const findingId = parts[3];
				const finding = await store.getFinding(scanId, findingId);
				if (!finding) throw new Error(`Unknown security finding: ${findingId}`);
				return createSecurityResource({
					url: `security://scans/${scanId}/findings/${findingId}`,
					content: formatFinding(finding),
					contentType: "text/markdown",
				});
			}
			case "coverage":
				if (parts.length !== 3) throw new Error(`Unknown security resource: security://${parts.join("/")}`);
				return createSecurityResource({
					url: `security://scans/${scanId}/coverage`,
					content: `${JSON.stringify(bundle.scan.coverage, null, 2)}\n`,
					contentType: "application/json",
				});
			case "report":
				if (parts.length !== 3) throw new Error(`Unknown security resource: security://${parts.join("/")}`);
				if (bundle.report === undefined) throw new Error(`Security scan ${scanId} has no report`);
				return createSecurityResource({
					url: `security://scans/${scanId}/report`,

View on GitHub (pinned to 9690622007)

Solutions

  1. Resolve security://scans/<id>/findings to list the valid finding ids in that scan and use one of them.
  2. Re-fetch the finding id after any scan re-run — ids are not guaranteed stable across runs.
  3. Confirm the finding id belongs to this scan, not another scan in the store.
  4. Check for truncation/typos in the id; ids are exact-match strings.

Example fix

// before
await resolve(new URL(`security://scans/${scanId}/findings/guessed-id`));
// after — enumerate first
const listing = await resolve(new URL(`security://scans/${scanId}/findings`));
// pick a listed finding id, then
await resolve(new URL(`security://scans/${scanId}/findings/${listedId}`));
Defensive patterns

Strategy: validation

Validate before calling

async function resolveExistingFinding(store: SecurityStore, scanId: string, findingId: string): Promise<SecurityFinding> {
  const finding = await store.getFinding(scanId, findingId);
  if (!finding) {
    const bundle = await store.getBundle(scanId);
    const ids = bundle?.findings.map(f => f.id).join(", ") ?? "none";
    throw new Error(`Finding "${findingId}" not in scan "${scanId}". Findings: ${ids}`);
  }
  return finding;
}

Type guard

async function findingExists(store: SecurityStore, scanId: string, findingId: string): Promise<boolean> {
  const bundle = await store.getBundle(scanId);
  return bundle?.findings.some(f => f.id === findingId) ?? false;
}

Try / catch

try {
  return await handler.resolve(url, ctx);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Unknown security finding:")) {
    const scanId = url.pathname.split("/").filter(Boolean)[1];
    return handler.resolve(new URL(`security://scans/${scanId}/findings`), ctx); // list valid ids
  }
  throw err;
}

Prevention

When it happens

Trigger: Resolving a finding URL with a finding id that was never in this scan, was fixed/disposed and pruned, belongs to a different scan, or was typo'd/truncated; resolving a stale finding id after the scan was re-run and ids changed.

Common situations: Re-running a scan invalidates previously cited finding ids (fingerprints/ids change between runs); agent cites a finding from an earlier conversation whose store was replaced; copying a finding id from a SARIF export of a different scan.

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/108640022aec4fb5. Report an issue: GitHub.