t8y2/dbx · critical

Server error

Error message

Server error

What it means

dbx-web runs axum::serve(listener, app).with_graceful_shutdown(ctrl_c) and expects the server future to complete without error. The expect fires when the serving loop terminates with an Err, i.e., a fatal server-side failure after startup.

Source

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

    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,
    };
    use crate::routes::table_import;
    use axum::body::Body;
    use axum::extract::{DefaultBodyLimit, Multipart};
    use axum::http::header::CONTENT_TYPE;
    use axum::http::{Response, StatusCode};
    use axum::routing::{get, post};
    use axum::Router;
    use tower_http::compression::predicate::Predicate;

View on GitHub (pinned to c0390bff16)

Solutions

  1. Check system logs / OS errors around the crash time (fd limits: ulimit -n, dmesg, container events).
  2. Raise the file descriptor limit and ensure the host does not forcibly close the socket.
  3. Run dbx-web under a supervisor (systemd/docker restart policy) so a fatal serve error triggers a restart.
  4. Replace expect() with error handling that logs the io::Error and performs graceful shutdown_state.shutdown() before exiting.

Example fix

// before
.await
.expect("Server error");
// after
.await
    .unwrap_or_else(|e| eprintln!("Server error: {e}"));
shutdown_state.shutdown(std::time::Duration::from_secs(3)).await;
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: ensure fd headroom for the accept loop
let fds_free = (unsafe { libc::getrlimit(libc::RLIMIT_NOFILE) }).rlim_cur > 1024;

Try / catch

if let Err(e) = axum::serve(listener, app)
    .with_graceful_shutdown(async { let _ = tokio::signal::ctrl_c().await; })
    .await
{
    tracing::error!("Server error: {e}");
}
shutdown_state.shutdown(std::time::Duration::from_secs(3)).await;

Prevention

When it happens

Trigger: axum::serve returns Err when the accept loop fails fatally — e.g., the listener socket becomes invalid, an OS-level accept error occurs repeatedly, or the runtime shuts down unexpectedly before ctrl_c.

Common situations: The listening socket being closed externally (container network teardown, firewall/security software); file-descriptor exhaustion (EMFILE) causing accept failures; abrupt process environment changes like the network interface disappearing.

Related errors


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