different-ai/openwork · error

Failed to open browser

Error message

Failed to open browser

What it means

openDesktopUrl first validates the URL, then calls the Electron shell bridge's openExternal. If the bridge reports a failure (`result.ok === false`), the error thrown is the bridge's own `result.error`, or the generic 'Failed to open browser' when the bridge supplied no error detail. It signals the OS-level open of the default browser failed, not a URL problem.

Source

Thrown at apps/app/src/app/lib/desktop.ts:489

  let parsed: URL;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error("Only valid web links can be opened externally.");
  }
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
    throw new Error(`External URL protocol "${parsed.protocol}" is not allowed.`);
  }
  return parsed.toString();
}

export async function openDesktopUrl(url: string): Promise<void> {
  const safeUrl = assertDesktopWebUrl(url);
  const openExternal = window.__OPENWORK_ELECTRON__?.shell?.openExternal;
  if (openExternal) {
    const result = await openExternal(safeUrl);
    if (result && result.ok === false) {
      throw new Error(result.error ?? "Failed to open browser");
    }
    return;
  }
  if (typeof window !== "undefined") {
    window.open(safeUrl, "_blank", "noopener,noreferrer");
  }
}

export async function openDesktopPath(target: string): Promise<void> {
  const result = await invokeElectronHelper("__openPath", target);
  if (typeof result === "string" && result.trim()) {
    throw new Error(result);
  }
}

export async function revealDesktopItemInDir(target: string): Promise<void> {
  const result = await invokeElectronHelper("__revealItemInDir", target);
  if (typeof result === "string" && result.trim()) {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Set/repair the OS default browser (Settings → Default apps, or `xdg-settings set default-web-browser firefox.desktop` on Linux) and retry.
  2. Use the fallback path by ensuring the bridge is absent only in web contexts — in web builds window.open handles it; if in Electron and it persistently fails, fall back to `window.open(safeUrl, "_blank", "noopener,noreferrer")` in the renderer.
  3. Check the Electron main process logs around shell.openExternal for the underlying OS error.
  4. Retry after restarting the desktop app if the failure followed a browser uninstall/update while the app was running.

Example fix

// before
await openDesktopUrl(link);

// after
try {
  await openDesktopUrl(link);
} catch (err) {
  console.error("openExternal failed, falling back", err);
  window.open(link, "_blank", "noopener,noreferrer");
}
Defensive patterns

Strategy: fallback

Try / catch

try {
  await openDesktopUrl(url);
} catch (err) {
  console.error("openExternal failed", err);
  window.open(url, "_blank", "noopener,noreferrer");
}

Prevention

When it happens

Trigger: `window.__OPENWORK_ELECTRON__.shell.openExternal(safeUrl)` resolving with `{ ok: false }` and no `error` message — e.g. the main process failed to spawn the default browser, no browser is registered, or the OS handler invocation returned an error without a detail string.

Common situations: Linux desktop environments without a default browser configured (xdg-open fails); sandboxed/flatpak builds missing portal permissions to launch external apps; a corporate machine with locked-down default app associations; a stale/removed default browser.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/f885442b96e0c8ec. Report an issue: GitHub.