HKUDS/nanobot · error · TuiUnavailableError

local gateway did not become ready; logs

Error message

local gateway did not become ready; logs: {result.status.log_path}

What it means

In _ensure_gateway/wait_for_ready, the newly started gateway process ran for the readiness window but never exposed its WebSocket/WebUI listener (and its health never became ready). Either it exited or stayed unready past the ~20s deadline; the launcher surfaces the log path so the startup failure can be diagnosed.

Solutions

  1. Inspect the gateway log file given in the message for the startup error
  2. Fix the cause (bad channel/provider config, missing dependencies) and rerun `nanobot agent`
  3. Increase readiness tolerance only if startup is legitimately slow
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at nanobot/cli/tui_launcher.py:461 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of HKUDS/nanobot@42f37dc4c0 (2026-08-26). Data as JSON: /api/errors/a789b6024b8ae907. Report an issue: GitHub.

Appendix: source

Thrown at nanobot/cli/tui_launcher.py:461

        if not wait_until_ready:
            return _GatewayHandle(base_url=base_url, lease=lease)

        deadline = time.monotonic() + 20
        while time.monotonic() < deadline:
            if _webui_endpoint_reachable(base_url):
                current = runtime.status()
                if current.running and current.port in {None, config.gateway.port}:
                    return _GatewayHandle(base_url=base_url, lease=lease)
                break
            if not runtime.status().running and not _gateway_health_ready(
                config.gateway.host,
                config.gateway.port,
            ):
                break
            time.sleep(0.1)

        raise TuiUnavailableError(
            f"local gateway did not become ready; logs: {result.status.log_path}"
        )
    except BaseException:
        lease.release(timeout_s=5)
        raise


def _tui_gateway_connection(config: Config) -> tuple[str, str]:
    """Read the small bootstrap subset without importing the WebSocket runtime."""
    raw: object = getattr(config.channels, "websocket", None)
    settings = cast(dict[str, Any], raw) if isinstance(raw, dict) else {}
    host = _host_for_local_browser(str(settings.get("host") or "127.0.0.1"))
    try:
        port = int(settings.get("port") or 8765)
    except (TypeError, ValueError):
        port = 8765
    secret = str(
        settings.get("tokenIssueSecret")

View on GitHub (pinned to 42f37dc4c0)