Hmbown/CodeWhale · error

Codewhale mobile is loopback-only without TLS or a verified…

Error message

Codewhale mobile is loopback-only without TLS or a verified overlay; bind to 127.0.0.1 or ::1

What it means

Mobile control over the Runtime API is plain HTTP with no TLS or verified overlay, so binding to a non-loopback host would expose it to peers that can observe or replay traffic. This bail enforces loopback binding (127.0.0.1 or ::1) whenever mobile mode is on.

Solutions

  1. Bind to 127.0.0.1 or ::1
  2. Reach the runtime from the mobile device via an SSH tunnel or VPN loopback forward
  3. Use the pairing/overlay mechanism instead of a raw non-loopback bind

Example fix

// before
codewhale runtime --mobile --host 0.0.0.0
// after
codewhale runtime --mobile --host 127.0.0.1
Defensive patterns

Strategy: validation

Validate before calling

const LOOPBACK: [&str; 2] = ["127.0.0.1", "::1"];
if mobile_enabled && !LOOPBACK.contains(&host.as_str()) { return Err("mobile mode requires a loopback bind".into()); }

Prevention

When it happens

Trigger: Starting the Runtime API with mobile enabled and `is_loopback_bind_host(&options.host)` false — e.g. `--host 0.0.0.0`, an LAN IP, or a hostname resolving off-loopback.

Common situations: Trying to use the mobile app from another device by binding 0.0.0.0; Docker/container defaults binding all interfaces; assuming mobile mode implies a secure transport.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/a69551af29b17487. Report an issue: GitHub.

Appendix: source

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

    task_manager.shutdown_and_wait().await?;
    serve_result
}

/// Mobile control uses plain HTTP only on loopback. It has no TLS or verified
/// overlay transport, so a non-loopback listener would expose the Runtime API
/// to peers that can observe or replay browser traffic.
fn validate_runtime_listener_security(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");
    }
    if options.mobile && !is_loopback_bind_host(&options.host) {
        bail!(
            "Codewhale mobile is loopback-only without TLS or a verified overlay; bind to 127.0.0.1 or ::1"
        );
    }
    if options.insecure_no_auth && !is_loopback_bind_host(&options.host) {
        bail!(
            "Unauthenticated Runtime access is loopback-only; remove --insecure or bind to 127.0.0.1 or ::1"
        );
    }
    Ok(())
}

fn is_loopback_bind_host(host: &str) -> bool {
    host.parse::<IpAddr>()
        .is_ok_and(|address| address.is_loopback())
}

fn runtime_bind_address(host: &str, port: u16) -> Result<SocketAddr> {
    let address = match host.parse::<IpAddr>() {

View on GitHub (pinned to 73e0f67d83)