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

  1. Construct the targetUrl with an explicit scheme by building the string "http://" + host + ":" + port and passing it through new URL(...).toString().
  2. Validate the URL parses on the caller side before invoking the register IPC.
  3. 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

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


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/3defc5905a8ac261. Report an issue: GitHub.