{"record":{"id":"108640022aec4fb5","repo":"can1357/oh-my-pi","slug":"unknown-security-finding-findingid","errorCode":null,"errorMessage":"Unknown security finding: ${findingId}","messagePattern":"Unknown security finding: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/security-protocol.ts","lineNumber":195,"sourceCode":"\t\t\tcase \"findings\": {\n\t\t\t\tif (parts.length === 3) {\n\t\t\t\t\tconst listing = bundle.findings.map(finding =>\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t`- \\`${finding.id}\\` **${finding.severity.level}** — ${sanitizeText(finding.title)}`,\n\t\t\t\t\t\t\t` (\\`${sanitizeText(finding.ruleId)}\\`)`,\n\t\t\t\t\t\t].join(\"\"),\n\t\t\t\t\t);\n\t\t\t\t\treturn createSecurityResource({\n\t\t\t\t\t\turl: `security://scans/${scanId}/findings`,\n\t\t\t\t\t\tcontent: `# Findings for ${scanId}\\n\\n${listing.length > 0 ? listing.join(\"\\n\") : \"No findings.\"}\\n`,\n\t\t\t\t\t\tcontentType: \"text/markdown\",\n\t\t\t\t\t\tisDirectory: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (parts.length !== 4) throw new Error(`Unknown security resource: security://${parts.join(\"/\")}`);\n\t\t\t\tconst findingId = parts[3];\n\t\t\t\tconst finding = await store.getFinding(scanId, findingId);\n\t\t\t\tif (!finding) throw new Error(`Unknown security finding: ${findingId}`);\n\t\t\t\treturn createSecurityResource({\n\t\t\t\t\turl: `security://scans/${scanId}/findings/${findingId}`,\n\t\t\t\t\tcontent: formatFinding(finding),\n\t\t\t\t\tcontentType: \"text/markdown\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tcase \"coverage\":\n\t\t\t\tif (parts.length !== 3) throw new Error(`Unknown security resource: security://${parts.join(\"/\")}`);\n\t\t\t\treturn createSecurityResource({\n\t\t\t\t\turl: `security://scans/${scanId}/coverage`,\n\t\t\t\t\tcontent: `${JSON.stringify(bundle.scan.coverage, null, 2)}\\n`,\n\t\t\t\t\tcontentType: \"application/json\",\n\t\t\t\t});\n\t\t\tcase \"report\":\n\t\t\t\tif (parts.length !== 3) throw new Error(`Unknown security resource: security://${parts.join(\"/\")}`);\n\t\t\t\tif (bundle.report === undefined) throw new Error(`Security scan ${scanId} has no report`);\n\t\t\t\treturn createSecurityResource({\n\t\t\t\t\turl: `security://scans/${scanId}/report`,","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/security-protocol.ts#L177-L213","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait resolve(new URL(`security://scans/${scanId}/findings/guessed-id`));\n// after — enumerate first\nconst listing = await resolve(new URL(`security://scans/${scanId}/findings`));\n// pick a listed finding id, then\nawait resolve(new URL(`security://scans/${scanId}/findings/${listedId}`));","handlingStrategy":"validation","validationCode":"async function resolveExistingFinding(store: SecurityStore, scanId: string, findingId: string): Promise<SecurityFinding> {\n  const finding = await store.getFinding(scanId, findingId);\n  if (!finding) {\n    const bundle = await store.getBundle(scanId);\n    const ids = bundle?.findings.map(f => f.id).join(\", \") ?? \"none\";\n    throw new Error(`Finding \"${findingId}\" not in scan \"${scanId}\". Findings: ${ids}`);\n  }\n  return finding;\n}","typeGuard":"async function findingExists(store: SecurityStore, scanId: string, findingId: string): Promise<boolean> {\n  const bundle = await store.getBundle(scanId);\n  return bundle?.findings.some(f => f.id === findingId) ?? false;\n}","tryCatchPattern":"try {\n  return await handler.resolve(url, ctx);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Unknown security finding:\")) {\n    const scanId = url.pathname.split(\"/\").filter(Boolean)[1];\n    return handler.resolve(new URL(`security://scans/${scanId}/findings`), ctx); // list valid ids\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["internal-urls","not-found","stale-reference"],"backgroundTag":"resource-not-found","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}