Hmbown/CodeWhale · error

Codewhale web is loopback-only and must bind to 127.0.0.1

Error message

Codewhale web is loopback-only and must bind to 127.0.0.1

What it means

When the Codewhale web UI is enabled (options.web), run_http_server enforces that the bind host is exactly 127.0.0.1. The web surface is designed loopback-only: exposing it to the network is refused at startup rather than relying on the operator to bind safely. Any --host other than 127.0.0.1 combined with web mode triggers this bail.

Source

Thrown at crates/tui/src/runtime_api.rs:835

        workspace,
        manager_config,
        plugin_registry,
    )?);
    Ok((manager, workshop_activation))
}

/// Start the runtime API server.
pub async fn run_http_server(
    config: Config,
    workspace: PathBuf,
    plugin_discovery: Arc<crate::plugins::PluginDiscoveryContext>,
    options: RuntimeApiOptions,
) -> Result<()> {
    if options.port == 0 {
        bail!("Port must be > 0");
    }
    if options.web && options.host != "127.0.0.1" {
        bail!("Codewhale web is loopback-only and must bind to 127.0.0.1");
    }
    if options.web && options.insecure_no_auth {
        bail!("Codewhale web requires Runtime authentication; remove --insecure");
    }

    let task_cfg = TaskManagerConfig::from_runtime(
        &config,
        workspace.clone(),
        config.default_text_model.clone(),
        Some(options.workers),
    );
    let (runtime_threads, _workshop_activation) = open_runtime_threads_for_server(
        &config,
        workspace.clone(),
        RuntimeThreadManagerConfig::from_task_data_dir(task_cfg.data_dir.clone()),
        plugin_discovery.registry_for_workspace(&workspace),
    )?;
    let task_manager =

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Keep web mode on the default loopback bind: set host to exactly 127.0.0.1.
  2. To reach the web UI remotely, keep the loopback bind and tunnel (SSH port-forward) instead of widening the bind.
  3. If you only meant to run the non-web runtime API on another interface, drop --web so the loopback restriction no longer applies (subject to your own exposure policy).

Example fix

# before
codewhale serve --web --host 0.0.0.0 --port 8080   # bails: loopback-only

# after
ssh -L 8080:127.0.0.1:8080 user@host &
codewhale serve --web --host 127.0.0.1 --port 8080   # open http://127.0.0.1:8080 locally
Defensive patterns

Strategy: validation

Validate before calling

// Rust: enforce the web-mode binding contract at the call site
if options.web {
    anyhow::ensure!(
        options.host == "127.0.0.1",
        "web mode requires host 127.0.0.1, got {}",
        options.host
    );
}
run_http_server(config, workspace, discovery, options).await?;

Prevention

When it happens

Trigger: Starting the server with web enabled and --host 0.0.0.0, a LAN IP, or a hostname such as localhost; passing a custom host for the plain API while also enabling --web.

Common situations: Operators try to serve the web UI from a container or remote VM by binding 0.0.0.0; docker port-mapping setups that require a wildcard bind; users passing 'localhost' expecting it to be accepted (only the literal 127.0.0.1 is).

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/e2dcd720f319c52c. Report an issue: GitHub.