stablyai/orca · error · Error
Localhost label target is not a valid URL.
Error message
Localhost label target is not a valid URL.
What it means
Thrown by assertAllowedTarget when `new URL(targetUrl)` throws, i.e. the targetUrl passed to register a localhost worktree label route is not a parseable URL. This is the first guard in an SSRF-prevention chain: the proxy route must target a real URL before the hostname/port allowlist is checked.
Source
Thrown at src/main/ipc/localhost-worktree-labels.ts:35
ipcMain.handle(
'localhostWorktreeLabels:register',
async (_event, rawArgs: unknown): Promise<LocalhostWorktreeLabelResult> => {
const route = parseRegisterArgs(rawArgs)
// Why: the proxy will forward to any host it's given, so we restrict the
// target to loopback or a host:port that matches a live workspace port —
// otherwise this IPC is an open proxy / SSRF vector.
await assertAllowedTarget(store, route.targetUrl)
return localhostWorktreeLabelProxy.registerRoute(route)
}
)
}
async function assertAllowedTarget(store: Store, targetUrl: string): Promise<void> {
let parsed: URL
try {
parsed = new URL(targetUrl)
} catch {
throw new Error('Localhost label target is not a valid URL.')
}
const targetHost = normalizeLocalhostHostname(parsed.hostname)
if (LOOPBACK_LOCALHOST_HOSTS.has(targetHost)) {
return
}
// Why: URL drops the port for protocol defaults (e.g. http://host/ on 80),
// so compare against the effective port rather than the raw (empty) string.
const targetPort = parsed.port || (parsed.protocol === 'https:' ? '443' : '80')
// Why (#11161): a metadata-skipped scan drops advertisedUrl, which would
// silently narrow this allowlist on an EDR-hooked host.
const scan = await scanWorkspacePortProbes(getStoreWorkspacePortProbes(store), {
requireMetadata: true
})
const matches = scan.ports.some((port) => {
if (String(port.port) !== targetPort) {
return false
}View on GitHub (pinned to 1136503c6a)
Solutions
- Construct the targetUrl with an explicit scheme by building the string "http://" + host + ":" + port and passing it through new URL(...).toString().
- Validate the URL parses on the caller side before invoking the register IPC.
- Ensure host and port are non-empty when building the URL string.
Example fix
// before
await ipc.call('localhostLabel:register', { targetUrl: `${host}:${port}`, ... })
// after
const targetUrl = new URL(`http://${host}:${port}`).toString()
await ipc.call('localhostLabel:register', { targetUrl, ... }) Defensive patterns
Strategy: validation
Validate before calling
let parsed: URL
try {
parsed = new URL(targetUrl)
} catch {
throw new Error('targetUrl must be a valid URL with scheme')
} Type guard
function isParsableUrl(value: unknown): value is string {
if (typeof value !== 'string') return false
try { new URL(value); return true } catch { return false }
} Prevention
- Always build targetUrl with an explicit scheme via new URL(`http://${host}:${port}`).
- Validate the URL parses on the caller side before registering.
- Never pass a bare host:port string without a protocol.
When it happens
Trigger: Calling the localhost-worktree-labels register IPC with a targetUrl that is empty, missing the scheme, contains invalid characters, or is otherwise unparseable by the URL constructor. Examples: 'localhost:3000' (no scheme), 'ht!tp://x', ''.
Common situations: Renderer constructs the URL from a port number without prepending 'http://'. User-entered target omits the protocol. A template/string-build bug yields an empty or malformed URL.
Related errors
- Localhost label target is not an allowed workspace port.
- Access denied: invalid worktree path
- Invalid localhost label route.
- Invalid localhost label ${field}.
- Invalid renderer output path: ${String(outputPath)}
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/3defc5905a8ac261.
Report an issue: GitHub.