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

  1. Use the documented namespace root: security://scans (see the security:// index page which lists valid children).
  2. Fix typos in the first path segment — only "scans" is valid.
  3. 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>).
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/351d37f01a7b4949. Report an issue: GitHub.