Hmbown/CodeWhale · critical · anyhow::Error

app-server auth token cannot be empty

Error message

app-server auth token cannot be empty

What it means

The app-server resolves its authentication token from AppServerOptions before binding. If an auth_token was explicitly configured but consists only of whitespace after trimming, resolve_auth_token bails with this error. An explicitly-set-but-empty token is treated as a misconfiguration that must fail loudly rather than silently degrading to no-auth or a generated token.

Solutions

  1. Provide a real non-empty token in AppServerOptions.auth_token
  2. Fix the environment variable or config file so it contains the actual secret
  3. If you truly want no authentication, explicitly set insecure_no_auth (loopback binds only) instead of an empty token
  4. Unset/omit the auth_token field entirely so the server's default token resolution applies

Example fix

// before
let opts = AppServerOptions { auth_token: Some("".into()), .. };
// after
let opts = AppServerOptions { auth_token: Some(real_token), .. };
Defensive patterns

Strategy: validation

Validate before calling

let auth_token = env::var("APP_SERVER_AUTH_TOKEN").unwrap_or_default();
if !auth_token.trim().is_empty() {
    opts.auth_token = Some(auth_token);
} // else leave unset so the server's default resolution applies

Type guard

fn has_token(t: &Option<String>) -> bool { t.as_deref().map_or(false, |s| !s.trim().is_empty()) }

Try / catch

match app_server::run(opts) {
    Err(e) if e.to_string().contains("auth token cannot be empty") => {
        eprintln!("auth_token configured but blank; fix APP_SERVER_AUTH_TOKEN or set insecure_no_auth");
        std::process::exit(2);
    }
    r => r,
}

Prevention

When it happens

Trigger: Constructing AppServerOptions with auth_token: Some("") or Some(" ") and starting the server; loading the token from a config file or environment variable that is present but blank.

Common situations: An env var like APP_SERVER_AUTH_TOKEN set to an empty string in a deployment manifest; a config template with `auth_token = ""` left unfilled; CI injecting a secret that resolved to empty.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at crates/app-server/src/lib.rs:876

    Ok(AppState {
        config_path,
        config: Arc::new(RwLock::new(config)),
        runtime: Arc::new(RwLock::new(runtime)),
        registry,
        auth_token,
        runtime_bridge: Arc::new(Mutex::new(None)),
        runtime_thread_map: Arc::new(Mutex::new(HashMap::new())),
        stdio_thread_hints: Arc::new(Mutex::new(HashMap::new())),
        in_flight_turns: Arc::new(Mutex::new(HashMap::new())),
    })
}

fn resolve_auth_token(options: &AppServerOptions) -> Result<Option<String>> {
    let configured = options.auth_token.as_ref().map(|token| token.trim());
    if let Some(token) = configured
        && token.is_empty()
    {
        bail!("app-server auth token cannot be empty");
    }
    let has_explicit_token = configured.is_some();

    if options.insecure_no_auth {
        if !options.listen.ip().is_loopback() {
            bail!("refusing unauthenticated app-server bind on non-loopback address");
        }
        eprintln!("warning: app-server HTTP auth disabled by --insecure-no-auth");
        return Ok(None);
    }

    if !has_explicit_token && !options.listen.ip().is_loopback() {
        bail!(
            "refusing non-loopback app-server bind without explicit auth token; pass --auth-token or set CODEWHALE_APP_SERVER_TOKEN"
        );
    }

    let token = configured

View on GitHub (pinned to 73e0f67d83)