t8y2/dbx · critical

Failed to bind address

Error message

Failed to bind address

What it means

Panics/aborts in dbx-web main when binding the HTTP listener to 0.0.0.0:DBX_PORT (default 4224) fails — the port is already in use or lacks bind permissions. The server cannot accept connections, so startup terminates after logging the bind failure.

Source

Thrown at crates/dbx-web/src/main.rs:1125

    let static_dir = std::env::var_os("DBX_STATIC_DIR").map(std::path::PathBuf::from);
    app = mount_public_base_path(app, &public_base_path, static_dir.as_deref());

    // Bind address
    let port: u16 = std::env::var("DBX_PORT").ok().and_then(|p| p.parse().ok()).unwrap_or(4224);
    let addr = SocketAddr::from(([0, 0, 0, 0], port));

    tracing::info!("DBX Web server starting on http://{}", addr);
    if public_base_path != "/" {
        tracing::info!("Serving DBX Web under context path {}", public_base_path);
    }
    if password_disabled {
        tracing::info!("Password protection is disabled");
    } else if std::env::var("DBX_PASSWORD").is_ok() {
        tracing::info!("Password protection is enabled");
    }

    let listener = tokio::net::TcpListener::bind(addr).await.expect("Failed to bind address");
    let shutdown_state = web_state.app.clone();
    axum::serve(listener, app)
        .with_graceful_shutdown(async {
            if let Err(error) = tokio::signal::ctrl_c().await {
                tracing::warn!("Failed to listen for shutdown signal: {error}");
            }
        })
        .await
        .expect("Server error");
    shutdown_state.shutdown(std::time::Duration::from_secs(3)).await;
}

#[cfg(test)]
mod tests {
    use super::{
        mount_public_base_path, normalize_public_base_path, web_agent_dir_from_env, web_body_limit_bytes_from_value,
        web_compression_predicate, XLSX_CONTENT_TYPE,
    };

View on GitHub (pinned to c0390bff16)

Solutions

  1. Free the port: find and stop the process using it (lsof -i :PORT / netstat) or choose a different port via DBX_PORT.
  2. Set DBX_HOST to 0.0.0.0 (or a valid local IP) and a non-privileged port, or grant binding capabilities.
  3. Check IPv6 availability if binding '::' — use '0.0.0.0' on IPv4-only hosts.
  4. Configure SO_REUSEADDR equivalent or ensure a graceful shutdown of the previous instance before restart.

Example fix

// before
let listener = tokio::net::TcpListener::bind(addr).await.expect("Failed to bind address");
// after
let listener = tokio::net::TcpListener::bind(&addr).await
    .unwrap_or_else(|e| panic!("Failed to bind address {}: {e}", addr));
Defensive patterns

Strategy: validation

Validate before calling

use std::net::TcpListener;
fn port_free(addr: &str) -> bool {
    addr.to_socket_addrs().ok()
        .and_then(|mut a| a.next())
        .map(|a| TcpListener::bind(a).is_ok())
        .unwrap_or(false)
}
// call before starting: assert!(port_free("127.0.0.1:8080"));

Try / catch

match tokio::net::TcpListener::bind(&addr).await {
    Ok(l) => l,
    Err(e) if e.kind() == std::io::ErrorKind::AddrInUse => {
        eprintln!("Port in use at {addr}; stop the other process or change DBX_PORT");
        std::process::exit(1);
    }
    Err(e) => { eprintln!("Failed to bind {addr}: {e}"); std::process::exit(1); }
}

Prevention

When it happens

Trigger: TcpListener::bind(addr) fails because the port is already in use, the address is not a local interface, or the process lacks permission to bind (e.g., privileged port <1024 without capabilities).

Common situations: Another instance of dbx-web (or a leftover process) holding the port; DBX_HOST/DBX_PORT set to a bad or in-use combination; binding port 80/443 as non-root in a container; IPv6 address specified on a host without IPv6.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/5f2d168b10f57bba. Report an issue: GitHub.