garrytan/gstack · error · Error

[browse] Server unresponsive after retry — aborting

Error message

[browse] Server unresponsive after retry — aborting

What it means

Error "[browse] Server unresponsive after retry — aborting" thrown in garrytan/gstack.

Source

Thrown at browse/src/cli.ts:594

      // #1781: a 30s timeout on a heavy page usually means busy, not dead.
      // Don't kill a live server (that's what triggered the crash-loop) — report
      // and exit so the user can retry rather than losing their (headed) window.
      const ts = readState();
      const alive = ts?.pid ? isProcessAlive(ts.pid) : false;
      console.error(alive
        ? '[browse] Command timed out after 30s (server still alive — busy, not restarting). Retry, or raise load.'
        : '[browse] Command timed out after 30s');
      process.exit(1);
    }
    // Connection error — server may have crashed, OR may just be busy.
    if (err.code === 'ECONNREFUSED' || err.code === 'ECONNRESET' || err.message?.includes('fetch failed')) {
      const oldState = readState();
      // #1781 busy-vs-dead: a single-threaded daemon under beacon/extension load
      // can briefly stop answering HTTP while still alive. Before declaring a
      // crash, if the process is alive give /health a bounded chance to recover
      // and just retry the command — never kill+restart a live-but-busy server.
      if (oldState?.pid && isProcessAlive(oldState.pid) && await probeHealthWithBackoff(oldState.port)) {
        if (retries >= 1) throw new Error('[browse] Server unresponsive after retry — aborting');
        console.error('[browse] Server was briefly unresponsive (busy); retrying command...');
        return sendCommand(oldState, command, args, retries + 1);
      }
      // Truly dead (or health never recovered) → restart.
      if (retries >= 1) throw new Error('[browse] Server crashed twice in a row — aborting');
      console.error('[browse] Server connection lost. Restarting...');
      if (oldState && oldState.pid) {
        await killServer(oldState.pid);
      }
      // startServer() now clears the Chromium SingletonLock + reaps the orphan,
      // so the relaunch isn't blocked by the dead Chromium's profile lock (#1781).
      //
      // Reapply --proxy / --headed when restarting. headed comes from THIS
      // invocation OR the persisted server mode, so a restart triggered by a
      // plain command (goto/status, no --headed) never silently downgrades a
      // headed session to headless (#1781). Same for proxy/configHash.
      const restartEnv = buildRestartEnv(_globalFlags, oldState);
      const newState = await startServer(Object.keys(restartEnv).length ? restartEnv : undefined);

View on GitHub (pinned to 94993f7401)

When it happens

Trigger: Thrown at browse/src/cli.ts:594 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/bcd94384f8156586. Report an issue: GitHub.