{"record":{"id":"e7aac9027fd4a442","repo":"gitbutlerapp/gitbutler","slug":"failed-to-bind-to-url-e","errorCode":null,"errorMessage":"Failed to bind to {url}: {e}","messagePattern":"Failed to bind to (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-server/src/lib.rs","lineNumber":848,"sourceCode":"    let default_host = \"127.0.0.1\";\n    let host_env = std::env::var(\"BUTLER_HOST\").ok();\n    let host = config\n        .bind_addr\n        .as_deref()\n        .or(host_env.as_deref())\n        .unwrap_or(default_host);\n    let url = format!(\"{host}:{port}\");\n    let listener = match tokio::net::TcpListener::bind(&url).await {\n        Ok(listener) => listener,\n        Err(e) => {\n            if e.kind() == std::io::ErrorKind::AddrInUse {\n                tracing::error!(\n                    \"Failed to bind to {url}: {e}. Another instance of but-server may already be running on port {port}.\"\n                );\n            } else {\n                tracing::error!(\"Failed to bind to {url}: {e}\");\n            }\n            anyhow::bail!(\"Failed to bind to {url}: {e}\");\n        }\n    };\n    println!(\n        \"{} {}\",\n        \"Local:\".bold(),\n        format!(\"http://localhost:{port}\").cyan().underline()\n    );\n    let server = axum::serve(\n        listener,\n        app.into_make_service_with_connect_info::<SocketAddr>(),\n    );\n\n    tokio::select! {\n        result = server => { result.unwrap(); }\n        _ = tokio::signal::ctrl_c() => {\n            // The settings file watcher (spawn_blocking with infinite loop) and\n            // other background tasks prevent the tokio runtime from exiting\n            // cleanly. It's safe to terminate immediately.","sourceCodeStart":830,"sourceCodeEnd":866,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-server/src/lib.rs#L830-L866","documentation":"Public `run` in but-server binds a `tokio::net::TcpListener` to `host:port` (from config `bind_addr`, env `BUTLER_HOST`, or default 127.0.0.1, plus the chosen port) before serving the axum app. If the bind fails, the error is logged (with a special hint when the cause is `AddrInUse`) and re-raised as \"Failed to bind to {url}: {e}\", so the server never starts.","triggerScenarios":"Starting the server via `run` when `TcpListener::bind` fails: the port is already taken by another but-server/other process (AddrInUse), the port is privileged (<1024) without permission, the bind address is invalid or not local, or the port range is exhausted.","commonSituations":"Launching a second instance while one is already running (most common — the log explicitly hints at this); another service squatting on the port; typo'd BUTLER_HOST/bind_addr; docker/container networking where the address isn't assignable.","solutions":["Stop the existing process holding the port (find it with `lsof -i :<port>` on Unix or `netstat -ano` on Windows) or use another port.","Set the port/host via config `bind_addr` or the BUTLER_HOST env var to a valid local address.","If binding a privileged port, run with the required permissions or pick a port >= 1024.","Retry after transient bind failures, or add automatic port selection if the fixed port is expected to be free."],"exampleFix":"// before\nBUTLER_HOST=0.0.0.0 but-server --port 8585  // port taken by running instance\n// after\nlsof -ti :8585 | xargs kill   # or: BUTLER_HOST=127.0.0.1 but-server --port 8586","handlingStrategy":"retry","validationCode":"// Pre-flight: check the port is free before starting the server\nss -ltn | grep -q ':<port> ' && echo 'port in use' || echo 'port free'","typeGuard":"fn is_addr_in_use(err: &anyhow::Error) -> bool {\n    err.chain().any(|c| {\n        c.downcast_ref::<std::io::Error>()\n            .map(|io| io.kind() == std::io::ErrorKind::AddrInUse)\n            .unwrap_or(false)\n    })\n}","tryCatchPattern":"match but_server::run(config).await {\n    Err(e) if e.to_string().contains(\"Failed to bind\") && is_addr_in_use(&e) => {\n        // stop the existing instance or restart with a different port\n    }\n    other => other?,\n}","preventionTips":["Check for a running but-server instance before starting another one.","Make the port configurable (config bind_addr / BUTLER_HOST) and avoid hardcoding ports in scripts.","Use a port >= 1024 unless you have the privileges for a well-known port.","Validate the bind address is a valid local interface before launching.","Add automatic port selection or retry-with-next-port logic in orchestration scripts."],"tags":["network","bind","port-in-use","server"],"backgroundTag":"address-already-in-use","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}