decolua/9router · warning
[Tunnel] cloudflared exited unexpectedly, scheduling respawn
Error message
[Tunnel] cloudflared exited unexpectedly, scheduling respawn
What it means
During enableTunnel, the manager registers an unexpected-exit handler BEFORE spawning cloudflared so that even a crash-on-startup triggers it. When the spawned cloudflared process exits without being asked to stop, this warning is logged and the registered onUnexpectedExit callback schedules a respawn of the tunnel. It means the tunnel process died and automatic recovery is underway.
Source
Thrown at src/lib/tunnel/cloudflare/manager.js:76
killCloudflared(localPort);
console.log("[Tunnel] killed existing cloudflared");
throwIfCancelled(token);
const existing = loadState();
const shortId = existing?.shortId || generateShortId();
const onUrlUpdate = async (url) => {
if (token.cancelled) return;
console.log(`[Tunnel] url updated: ${url}`);
await registerTunnelUrl(shortId, url);
saveState({ shortId, tunnelUrl: url });
await updateSettings({ tunnelEnabled: true, tunnelUrl: url });
};
// Register exit handler BEFORE spawn so it fires even on early exit
setUnexpectedExitHandler(() => {
console.warn("[Tunnel] cloudflared exited unexpectedly, scheduling respawn");
if (onUnexpectedExit) onUnexpectedExit();
});
const { tunnelUrl } = await spawnQuickTunnel(localPort, onUrlUpdate);
console.log(`[Tunnel] spawned: ${tunnelUrl}`);
throwIfCancelled(token);
const publicUrl = `https://r${shortId}.abc-tunnel.us`;
await registerTunnelUrl(shortId, tunnelUrl);
saveState({ shortId, tunnelUrl });
await updateSettings({ tunnelEnabled: true, tunnelUrl });
console.log(`[Tunnel] registered shortId=${shortId} publicUrl=${publicUrl}`);
// Verify publicUrl first (worker route is reliable; direct *.trycloudflare.com DNS may lag)
await waitForHealth(publicUrl, token);
console.log("[Tunnel] public URL healthy");
// Direct tunnel probe is best-effort: DNS for *.trycloudflare.com can be slow/blocked
if (!(await probeUrlAlive(tunnelUrl))) {View on GitHub (pinned to 90b52e06ff)
Solutions
- Wait — the handler schedules a respawn automatically; verify a new '[Tunnel] spawned: <url>' line follows.
- Verify the cloudflared binary exists and is executable (and matches OS/arch); reinstall if needed.
- Check outbound network/VPN/firewall to Cloudflare edge (trycloudflare.com) and retry enabling the tunnel.
- Ensure no other process manages/kills cloudflared (duplicate tray/daemon instances) and that the local port is not occupied.
Example fix
// before: cloudflared not on PATH → spawn exits instantly, respawn loop
const { tunnelUrl } = await spawnQuickTunnel(localPort, onUrlUpdate);
// after: pre-check binary before enabling
if (!spawnSync("cloudflared", ["--version"], { stdio: "ignore" }).error) {
const { tunnelUrl } = await spawnQuickTunnel(localPort, onUrlUpdate);
} Defensive patterns
Strategy: retry
Validate before calling
// ensure cloudflared is available before enabling the tunnel
import { spawnSync } from "child_process";
const check = spawnSync("cloudflared", ["--version"], { stdio: "ignore" });
if (check.error) throw new Error("cloudflared not installed or not on PATH"); Try / catch
// tolerate transient exits; rely on auto-respawn, alert only on repeated failures
let respawnCount = 0;
setUnexpectedExitHandler(() => {
if (++respawnCount > 5) console.error("[Tunnel] repeated cloudflared crashes — check binary/network");
}); Prevention
- Install the correct cloudflared binary for your OS/arch and keep it on PATH.
- Ensure stable network egress to Cloudflare (no blocking VPN/firewall).
- Avoid running multiple instances that manage the same cloudflared process.
- Prevent system sleep/suspend during tunnel use.
When it happens
Trigger: cloudflared terminates on its own during or after spawnQuickTunnel: binary missing/corrupt, network dropped, Cloudflare edge connection closed, port conflict, OOM kill, or early-exit due to bad flags. Also fires after an external 'taskkill cloudflared' or systemd/launchd interference.
Common situations: Laptops sleeping/waking and killing the process; corporate firewalls blocking Cloudflare egress; cloudflared not installed or wrong arch binary; running multiple instances fighting over cloudflared; VPN dropping mid-session.
Related errors
- Health check timeout after ${HEALTH_CHECK.timeoutMs}ms
- [Tunnel] direct URL not reachable yet, continuing via public
- Unsupported platform: ${platform}
- cancelled
- tunnel cancelled
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/554bc40d08ddf160.
Report an issue: GitHub.