windmill-labs/windmill · warning
Failed to open browser: ${e.message}
Error message
Failed to open browser: ${e.message} What it means
`wmill pipeline dev` tries to open the pipeline dev URL in your default browser via the `open` package when --open is not false. If launching the browser fails, it logs this warning and continues — the server keeps running and the URL is printed, so you can open it manually.
Source
Thrown at cli/src/commands/pipeline/dev.ts:263
});
// The `/pipeline_dev` page is served by the frontend, not the backend. By
// default we open it on the workspace remote, but that 404s on a remote whose
// deployed frontend predates this route — `--frontend` points the page at a
// locally-run frontend (`REMOTE=<remote> npm run dev`) while the API/token
// still target the remote. Normalize to a single trailing slash either way.
const pageBase = (opts.frontend ?? workspace.remote).replace(/\/?$/, "/");
const url =
`${pageBase}pipeline_dev?workspace=${workspace.workspaceId}` +
`&wm_token=${workspace.token}&folder=${encodeURIComponent(folder)}&port=${port}` +
`&ws_token=${encodeURIComponent(wsToken)}`;
server.listen(port, LISTEN_HOST, () => {
log.info(colors.green.bold(`🚀 Pipeline dev server on ws://localhost:${port}/ws`));
log.info(colors.gray(`Open: ${url}`));
if (opts.open !== false) {
open.default(url).catch((e: any) =>
log.warn(colors.yellow(`Failed to open browser: ${e.message}`)),
);
}
});
process.on("SIGINT", () => {
log.info(colors.yellow("\n🛑 Shutting down…"));
watcher.close();
for (const ws of clients) ws.close();
server.close();
process.exit(0);
});
}
const command = new Command()
.description(
"Live-preview a data pipeline from local files: watch an `f/<folder>` of `// pipeline` scripts, push the working-tree graph to the dev page, and run the cascade via preview (no deploy).",
)
.arguments("[folder:string]")View on GitHub (pinned to e474e8803c)
Solutions
- Copy the `Open: <url>` line printed by the command into a browser manually — nothing else is broken.
- Pass --open=false (or --no-open) to suppress the attempt and the warning in headless environments.
- Install/configure a browser opener on the host (xdg-open, or set $BROWSER on Linux).
- Set DISPLAY/Wayland session variables if running from a non-GUI shell on a desktop machine.
Example fix
// before (headless box, warning every run) wmill pipeline dev // after wmill pipeline dev --open=false
Defensive patterns
Strategy: fallback
Validate before calling
// detect headless environment before relying on browser opening const headless = !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY && process.platform === 'linux'; const args = headless ? ['--open=false'] : [];
Try / catch
// the CLI already catches internally; when scripting, tolerate it
open.default(url).catch(e => {
console.warn(`browser failed (${e.message}); open ${url} manually`);
}); Prevention
- Pass --open=false on servers, containers, SSH and CI.
- Set $BROWSER or install xdg-open on minimal Linux images.
- Always print/copy the URL instead of relying on auto-open.
- In WSL, configure a Windows browser bridge.
When it happens
Trigger: server.listen succeeded and opts.open !== false, but the `open` promise rejects: no browser/xdg-open available, headless CI/SSH/container environment, DISPLAY/WAYLAND not set, or a malformed default-browser handler.
Common situations: Running in WSL without a Windows browser configured; SSH into a server with no GUI; Docker container; CI runner; Linux box without xdg-open; macOS default browser handler broken.
Related errors
- Could not find a free port in the range ${requested}-${reque
- Port ${requested} is already in use${holderHint}. Using port
- App ${appPath} not found
- Dependency generation failed: ${queueResponse.status} ${queu
- Failed to poll dependencies job ${jobId}: ${e?.message ?? e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/a64a553930023605.
Report an issue: GitHub.