can1357/oh-my-pi · error · SecurityDisabledError
Security disabled
Error message
Security disabled
What it means
The security:// protocol handler is gated behind the security.enabled setting. At the top of resolve(), if neither the ResolveContext settings nor the global settings report security.enabled === true, the handler throws SecurityDisabledError with the message "Security disabled" (expanded text tells the user to set security.enabled = true). This protects the read-only security scan namespace so it is only reachable when the user has opted in.
Source
Thrown at packages/coding-agent/src/internal-urls/security-protocol.ts:120
readonly scheme = "security";
readonly immutable = true;
readonly #resolveStore: SecurityStoreResolver;
readonly #enabled: () => boolean;
constructor(
resolveStore: SecurityStoreResolver = (cwd, signal) => SecurityStore.openForCwd(cwd, { signal }),
enabled: () => boolean = isSecurityEnabled,
) {
this.#resolveStore = resolveStore;
this.#enabled = enabled;
}
async #store(context?: ResolveContext): Promise<SecurityStore> {
return this.#resolveStore(path.resolve(context?.cwd ?? process.cwd()), context?.signal);
}
async resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {
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("/")}`);View on GitHub (pinned to 9690622007)
Solutions
- Enable the feature: set security.enabled = true in settings (Settings → Tools → Security) or via the settings API before resolving.
- If resolving programmatically, pass a ResolveContext whose settings.get("security.enabled") returns true.
- Check the return of isSecurityEnabled() before attempting security:// lookups and surface the enable-instructions message to the user instead of failing.
- If you expected it to be enabled, verify the settings file actually loaded (isSettingsInitialized) and that no project config overrides security.enabled to false.
Example fix
// before
const res = await handler.resolve(new URL("security://scans"));
// after
if (!isSecurityEnabled()) {
throw new Error("Enable security: set security.enabled = true in settings.");
}
const res = await handler.resolve(new URL("security://scans")); Defensive patterns
Strategy: type-guard
Validate before calling
import { isSecurityEnabled } from "./internal-urls/security-protocol";
async function resolveSecurityUrl(url: URL, context?: ResolveContext) {
if (!isSecurityEnabled()) {
throw new Error("security:// is disabled. Set security.enabled = true (Settings → Tools → Security).");
}
return securityHandler.resolve(url as InternalUrl, context);
} Type guard
function securityEnabledIn(context?: ResolveContext): boolean {
if (!context?.settings || typeof context.settings !== "object") return isSecurityEnabled();
try {
const get = Reflect.get(context.settings, "get");
if (typeof get !== "function") return isSecurityEnabled();
const enabled = Reflect.apply(get, context.settings, ["security.enabled"]);
return typeof enabled === "boolean" ? enabled : isSecurityEnabled();
} catch {
return isSecurityEnabled();
}
} Try / catch
try {
return await handler.resolve(url, ctx);
} catch (err) {
if (err instanceof SecurityDisabledError) {
logger.warn("security:// access attempted while disabled", { url: url.href });
return null; // or surface err.message to the user as guidance
}
throw err;
} Prevention
- Check isSecurityEnabled() (or your context settings) before building any security:// URL.
- Enable security.enabled in project settings for projects that use security scans.
- When passing ResolveContext, ensure settings.get("security.enabled") returns a boolean.
- Catch SecurityDisabledError by instanceof — it is an exported class, not a generic Error.
When it happens
Trigger: Calling SecurityProtocolHandler.resolve(url) (e.g. resolving security:// or security://scans/...) when (a) no context is passed and the global security.enabled setting is false (or unset and defaults to false), or (b) context.settings.get("security.enabled") returns false or a non-boolean, overriding to disabled.
Common situations: An agent or script tries to read security://scans on a fresh install where the feature was never enabled; a caller passes a ResolveContext whose settings object lacks a boolean for security.enabled; tests or embeddings construct the handler with the default isSecurityEnabled but never toggle the setting; a settings schema change leaves the default off.
Related errors
- Provider request limits must be positive numbers: ${invalidP
- Settings config was invalid before locking and is now missin
- Settings config is invalid and could not be moved aside: ${f
- Settings config is invalid: ${filePath}${result.backupPath ?
- Failed to read settings config ${filePath}: ${String(result.
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d1a409fcfbdef84a.
Report an issue: GitHub.