can1357/oh-my-pi · error
Unknown security resource: security://${parts.join("/")}
Error message
Unknown security resource: security://${parts.join("/")} What it means
After splitting a security:// URL into path segments, resolve() only recognizes "scans" as the first segment (the namespace root). Any other first segment — or a malformed deeper path — throws this "Unknown security resource" error echoing the reconstructed URL. It is a routing error: the URL does not match any resource in the security:// namespace.
Source
Thrown at packages/coding-agent/src/internal-urls/security-protocol.ts:138
if (!(securityEnabledFromContext(context) ?? this.#enabled())) throw new SecurityDisabledError();
const parts = splitSecurityPath(url);
const store = await this.#store(context);
if (parts.length === 0) {
return createSecurityResource({
url: "security://",
content: [
"# Security",
"",
"OMP-owned software-security analysis resources. The namespace is read-only; use explicit security commands or tools for mutations.",
"",
"- `security://scans` — list scans",
"",
].join("\n"),
contentType: "text/markdown",
isDirectory: true,
});
}
if (parts[0] !== "scans") throw new Error(`Unknown security resource: security://${parts.join("/")}`);
if (parts.length === 1) {
return createSecurityResource({
url: "security://scans",
content: formatScans(await store.listScans()),
contentType: "text/markdown",
isDirectory: true,
});
}
const scanId = parts[1];
const bundle = await store.getBundle(scanId);
if (!bundle) throw new Error(`Unknown security scan: ${scanId}`);
if (parts.length === 2) {
return createSecurityResource({
url: `security://scans/${scanId}`,
content: [
`# Security scan ${scanId}`,
"",
`- Status: **${bundle.scan.status}**`,View on GitHub (pinned to 9690622007)
Solutions
- Use the documented namespace root: security://scans (see the security:// index page which lists valid children).
- Fix typos in the first path segment — only "scans" is valid.
- Remove extra path segments: valid forms are security://, security://scans, security://scans/<id>, and security://scans/<id>/{manifest,findings,coverage,report,sarif,provenance} (plus .../findings/<findingId>).
- Use the handler's complete() method to enumerate valid security:// URLs instead of hand-building them.
Example fix
// before
await resolve(new URL("security://scan/abc123"));
// after
await resolve(new URL("security://scans/abc123")); Defensive patterns
Strategy: validation
Validate before calling
const SECURITY_ROOTS = new Set(["scans"]);
const SECURITY_CHILDREN = new Set(["manifest", "findings", "coverage", "report", "sarif", "provenance"]);
function validateSecurityUrl(parts: string[]): void {
if (parts.length === 0) return; // security:// index
if (!SECURITY_ROOTS.has(parts[0])) {
throw new Error(`Invalid security:// root "${parts[0]}"; expected "scans"`);
}
if (parts.length >= 3 && !SECURITY_CHILDREN.has(parts[2])) {
throw new Error(`Invalid security resource "${parts[2]}"; expected one of ${[...SECURITY_CHILDREN].join(", ")}`);
}
} Type guard
function isScansPath(parts: string[]): parts is ["scans", ...string[]] {
return parts.length > 0 && parts[0] === "scans";
}
// use: if (!isScansPath(parts)) { /* route elsewhere or fail fast */ } Try / catch
try {
return await handler.resolve(url, ctx);
} catch (err) {
if (err instanceof Error && err.message.startsWith("Unknown security resource:")) {
logger.warn("Unrecognized security:// URL", { url: url.href });
return await handler.resolve(new URL("security://"), ctx); // fall back to the index listing
}
throw err;
} Prevention
- Only use "scans" as the first path segment under security://.
- Build URLs from the completion() listing rather than string templates.
- Remember the namespace is flat: one level of resources under scans/<id>, nothing deeper except findings/<findingId>.
- Decode and filter empty segments before resolving user/model-provided URLs.
When it happens
Trigger: Resolving a URL like security://foo, security://scan/<id> (singular), security://scans/<id>/manifest/extra, or any typo'd top-level path where parts[0] !== "scans".
Common situations: Typos such as scan:// or security://scan/... instead of security://scans/...; hand-constructed URLs adding extra path segments under a resource; model-generated URLs inventing namespaces that don't exist; URL-encoded characters splitting into unexpected segments.
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 finding: ${findingId}
- 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/351d37f01a7b4949.
Report an issue: GitHub.