block/buzz · error · anyhow::Error

Server error

Error message

Server error: {e}

What it means

Identical failure point to 'TCP server error' but on the TCP-only code path of serve() (no UDS configured, non-unix or uds_path None): the axum::serve future for the main relay listener returned Err at crates/buzz-relay/src/main.rs:1390-1397. The bind already succeeded, so this is a runtime accept/serve-loop failure, not a startup config problem.

Solutions

  1. Raise fd limits (LimitNOFILE / ulimit -n) and check for fd growth: `ls /proc/<pid>/fd | wc -l` sampled over load.
  2. Extract the root cause from the anyhow chain — log with RUST_BACKTRACE=1 and RUST_LOG=buzz_relay=debug.
  3. Let the supervisor restart the relay; the graceful-shutdown wiring means a clean SIGTERM exit is normal, only a mid-run Err here is a defect.
  4. If correlated with media/git traffic, audit those handlers for leaked sockets/streams.
Defensive patterns

Strategy: try-catch

Validate before calling

# confirm healthy fd headroom before heavy traffic
[ "$(ulimit -n)" -ge 65536 ] || echo "warning: low fd limit" >&2

Try / catch

// map the terminal serve error to a clean exit code for the supervisor
let exit = async {
    if let Err(e) = serve(...).await {
        eprintln!("Server error: {e}");
        1
    } else { 0 }
};

Prevention

When it happens

Trigger: The graceful-shutdown-wrapped axum::serve on the main router errors with: persistent accept() failures (EMFILE/ENFILE when the process fd limit is exhausted by connection churn), ENOMEM, or errors escaping hyper's per-connection handling. It also fires if the tokio runtime is dropped while serve() is still running, making the future fail instead of being polled to completion.

Common situations: Default deployment (no BUZZ_UDS_PATH) under connection storms hitting `ulimit -n`; fd leaks from git smart-HTTP or Blossom media uploads starving accept; running the relay inside a harness that drops the runtime at test end and surfaces the cancelled serve as an error.

Related errors


AI-assisted analysis of block/buzz@ef2aa1ae38 (2026-08-20). Data as JSON: /api/errors/dc9627bf276af257. Report an issue: GitHub.

Appendix: source

Thrown at crates/buzz-relay/src/main.rs:1514

        return Ok(());
    }

    #[cfg(not(unix))]
    if config.uds_path.is_some() {
        tracing::warn!("BUZZ_UDS_PATH set but UDS not supported on this platform");
    }

    // TCP-only path.
    let mut tcp_rx = shutdown_tx.subscribe();
    axum::serve(
        tcp_listener,
        router.into_make_service_with_connect_info::<std::net::SocketAddr>(),
    )
    .with_graceful_shutdown(async move {
        tcp_rx.changed().await.ok();
    })
    .await
    .map_err(|e| anyhow::anyhow!("Server error: {e}"))?;

    let hard_shutdown = shutdown_handle
        .await
        .map_err(|e| anyhow::anyhow!("Shutdown task failed: {e}"))?;
    hard_shutdown.abort();
    Ok(())
}

/// Wait for SIGTERM (Unix) or Ctrl+C.
async fn shutdown_signal() {
    #[cfg(unix)]
    {
        use tokio::signal::unix::{signal, SignalKind};
        let mut sigterm = signal(SignalKind::terminate()).expect("install SIGTERM handler");
        tokio::select! {
            _ = tokio::signal::ctrl_c() => {},
            _ = sigterm.recv() => {},
        }

View on GitHub (pinned to ef2aa1ae38)