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
- Resolve security://scans/<id>/findings to list the valid finding ids in that scan and use one of them.
- Re-fetch the finding id after any scan re-run — ids are not guaranteed stable across runs.
- Confirm the finding id belongs to this scan, not another scan in the store.
- 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
- Always enumerate findings via security://scans/<id>/findings before deep-linking a specific id.
- Treat finding ids as per-run: refresh references after every re-scan.
- Confirm the id came from the same scan, not a different scan or an external SARIF file.
- Copy ids verbatim — no truncation, trimming, or case changes.
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
- Unknown security scan: ${scanId}
- Unknown security resource: security://${parts.join("/")}
- Plugin ${name} not found in runtime config
- Marketplace "${name}" not found
- Marketplace "${marketplace}" not found
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/108640022aec4fb5.
Report an issue: GitHub.