can1357/oh-my-pi · warning
Security scan ${scanId} has no report
Error message
Security scan ${scanId} has no report What it means
When security://scans/<id>/report is resolved with a valid shape, the handler checks bundle.report; if the scan bundle has no stored report (report === undefined), it throws "Security scan <scanId> has no report". A scan can complete without a human-readable report being generated (report generation is a separate artifact from findings/coverage/sarif).
Source
Thrown at packages/coding-agent/src/internal-urls/security-protocol.ts:211
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`,
content: bundle.report,
contentType: "text/markdown",
});
case "sarif":
if (parts.length !== 3) throw new Error(`Unknown security resource: security://${parts.join("/")}`);
if (bundle.sarif === undefined) throw new Error(`Security scan ${scanId} has no SARIF export`);
return createSecurityResource({
url: `security://scans/${scanId}/sarif`,
content: `${JSON.stringify(bundle.sarif, null, 2)}\n`,
contentType: "application/json",
});
case "provenance":
if (parts.length !== 3) throw new Error(`Unknown security resource: security://${parts.join("/")}`);
return createSecurityResource({
url: `security://scans/${scanId}/provenance`,
content: `${JSON.stringify(redactPrivateSecurityMetadata(bundle.scan.provenance), null, 2)}\n`,View on GitHub (pinned to 9690622007)
Solutions
- Check availability first: resolve the scan index (security://scans/<id>) or manifest and confirm a report exists before requesting it.
- Use alternative resources that are always present: security://scans/<id>/findings, .../coverage, or .../sarif.
- Re-run the security scan so the report artifact is generated, then resolve the report.
- Handle this error explicitly in callers and degrade to the findings listing instead of surfacing a hard failure.
Example fix
// before
const report = await resolve(new URL(`security://scans/${id}/report`));
// after
try {
var report = await resolve(new URL(`security://scans/${id}/report`));
} catch {
report = await resolve(new URL(`security://scans/${id}/findings`));
} Defensive patterns
Strategy: fallback
Validate before calling
async function reportAvailable(handler: SecurityProtocolHandler, scanId: string, ctx?: ResolveContext): Promise<boolean> {
const index = await handler.resolve(new URL(`security://scans/${scanId}`), ctx);
// The index page lists sub-resources; or check the manifest JSON:
const manifest = JSON.parse((await handler.resolve(new URL(`security://scans/${scanId}/manifest`), ctx)).content);
return manifest.report !== undefined || manifest.hasReport === true;
} Type guard
function bundleHasReport(bundle: { report?: string }): bundle is { report: string } {
return typeof bundle.report === "string";
}
// use before constructing the report URL when you hold the bundle Try / catch
try {
return await handler.resolve(new URL(`security://scans/${scanId}/report`), ctx);
} catch (err) {
if (err instanceof Error && /has no report$/.test(err.message)) {
// degrade gracefully: findings listing covers most report consumers
return handler.resolve(new URL(`security://scans/${scanId}/findings`), ctx);
}
throw err;
} Prevention
- Treat the report as an optional artifact — check the scan index or manifest before requesting it.
- Default to findings/coverage/sarif resources which are always present for completed scans.
- Re-run the scan if a report is required; partial or aborted scans may lack it.
- After version upgrades of the security tooling, assume older stored bundles may omit the report field.
When it happens
Trigger: Resolving the report resource for a scan whose bundle was created without report generation — e.g. a scan that was aborted before the report step, a scan produced by a tool that only emits findings/SARIF, or a bundle loaded from a store predating report support.
Common situations: An agent blindly follows the resource list (report is advertised as a child) for a scan that has none; partial/crashed scans persisted without the report artifact; older stores whose bundles lack the report field after a version upgrade.
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
- Output ${scan.matchedId} is not valid JSON: ${message}
- artifact:// URL requires a numeric ID: artifact://0
- artifact:// ID must be numeric, got: ${id}
- No session - artifacts unavailable
- No artifacts directory found
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/812d85215745f6c9.
Report an issue: GitHub.