BloopAI/vibe-kanban · error
client server address already set
Error message
client server address already set
What it means
set_server_addr stores the listener's local address in a once-only (OnceCell-style) field of client_info. The .expect("client server address already set") panics if the address was already initialized earlier in the process. It is an internal invariant check: server_addr must be set exactly once during startup.
Source
Thrown at crates/server/src/main.rs:136
let actual_main_port = main_listener.local_addr()?.port();
let proxy_listener = tokio::net::TcpListener::bind(format!("{host}:{proxy_port}")).await?;
let actual_proxy_port = proxy_listener.local_addr()?.port();
if let Err(e) = write_port_file_with_proxy(actual_main_port, Some(actual_proxy_port)).await {
tracing::warn!("Failed to write port file: {}", e);
}
tracing::info!(
"Main server on :{}, Preview proxy on :{}",
actual_main_port,
actual_proxy_port
);
deployment
.client_info()
.set_server_addr(main_listener.local_addr()?)
.expect("client server address already set");
deployment
.client_info()
.set_preview_proxy_port(actual_proxy_port)
.expect("client preview proxy port already set");
let app_router = routes::router(deployment.clone());
// Production only: open browser
if !cfg!(debug_assertions) {
tracing::info!("Opening browser...");
let browser_port = actual_main_port;
tokio::spawn(async move {
if let Err(e) =
utils::browser::open_browser(&format!("http://127.0.0.1:{browser_port}")).await
{
tracing::warn!(
"Failed to open browser automatically: {}. Please open http://127.0.0.1:{} manually.",
e,View on GitHub (pinned to 4deb7eca8f)
Solutions
- Verify set_server_addr is called exactly once in the startup path; remove duplicate calls.
- If the address may legitimately change, replace once-only semantics with set/replace (RwLock/Mutex) or .ok() instead of expect.
- Check that no retry/test wrapper re-runs the initialization block within the same process.
Example fix
// before
deployment.client_info().set_server_addr(main_listener.local_addr()?)
.expect("client server address already set");
// after
deployment.client_info()
.set_server_addr(main_listener.local_addr()?)
.unwrap_or_else(|_| tracing::warn!("server addr already set; keeping existing value")); Defensive patterns
Strategy: validation
Validate before calling
if deployment.client_info().server_addr().is_none() {
deployment.client_info()
.set_server_addr(main_listener.local_addr()?)?;
} Try / catch
deployment.client_info()
.set_server_addr(main_listener.local_addr()?)
.unwrap_or_else(|_| tracing::debug!("server addr already configured")); Prevention
- Call one-time initializers exactly once, from a single init function.
- Search the codebase for duplicate set_server_addr call sites before refactoring startup.
- Use .set().ok() or logged fallbacks instead of expect for idempotent-style setters.
- Add a unit test that runs the full startup path once to catch double-init regressions.
When it happens
Trigger: DeploymentImpl::new (or another startup path) already called client_info().set_server_addr() before line 136, so the second call finds the cell occupied and panics. Only reachable if startup code is duplicated or reordered.
Common situations: Modifying main.rs so initialization runs twice (re-created deployment, retried listener setup); merging code that sets the address in both a fallback and main path; refactoring that moved DeploymentImpl::new after address configuration.
Related errors
- client preview proxy port already set
- client server address already set
- client preview proxy port already set
- Default profiles v3 JSON is invalid
- request_id called for unsupported request variant
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/72fe10f33f994b11.
Report an issue: GitHub.