{"record":{"id":"df7f027eb98e524b","repo":"rust-lang/mdBook","slug":"unable-to-bind-to-address-e","errorCode":null,"errorMessage":"Unable to bind to {address}: {e}","messagePattern":"Unable to bind to (.+?): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/cmd/serve.rs","lineNumber":137,"sourceCode":"        let reload_tx = reload_tx_clone.clone();\n        ws.on_upgrade(move |socket| websocket_connection(socket, reload_tx))\n    };\n\n    let app = Router::new()\n        .route(&format!(\"/{LIVE_RELOAD_ENDPOINT}\"), get(websocket_handler))\n        .fallback_service(\n            ServeDir::new(&build_dir).not_found_service(ServeFile::new(build_dir.join(file_404))),\n        );\n\n    std::panic::set_hook(Box::new(move |panic_info| {\n        // exit if serve panics\n        error!(\"Unable to serve: {}\", panic_info);\n        std::process::exit(1);\n    }));\n\n    let listener = tokio::net::TcpListener::bind(&address)\n        .await\n        .unwrap_or_else(|e| panic!(\"Unable to bind to {address}: {e}\"));\n\n    axum::serve(listener, app).await.unwrap();\n}\n\nasync fn websocket_connection(ws: WebSocket, reload_tx: broadcast::Sender<Message>) {\n    let (mut user_ws_tx, _user_ws_rx) = ws.split();\n    let mut rx = reload_tx.subscribe();\n\n    trace!(\"websocket got connection\");\n    if let Ok(m) = rx.recv().await {\n        trace!(\"notify of reload\");\n        let _ = user_ws_tx.send(m).await;\n    }\n}\n","sourceCodeStart":119,"sourceCodeEnd":152,"githubUrl":"https://github.com/rust-lang/mdBook/blob/dc21064fc21d955a0e1f67e65e336883c3e5260b/src/cmd/serve.rs#L119-L152","documentation":"mdbook serve binds a tokio TcpListener on the configured address before serving the axum app. If the OS refuses the bind (address/port already in use, no permission, invalid address), the async bind returns an error and the code panics with `Unable to bind to {address}: {e}`. The message embeds both the attempted address and the underlying io::Error.","triggerScenarios":"Running `mdbook serve` on a port already occupied by another process, binding to a privileged port (<1024) without permissions, specifying an IP address not assigned to any local interface, or starting two `mdbook serve` instances concurrently.","commonSituations":"Port 3000 already used by another dev server, a previous mdbook serve instance that didn't exit, Docker/WSL port conflicts, or --hostname set to a public IP the machine doesn't own.","solutions":["Choose a free port: mdbook serve -p 3001 (or any unused port).","Find and stop the process holding the port: lsof -i :3000 or ss -ltnp, then kill it.","Bind to a valid local interface: use --hostname 127.0.0.1 or 0.0.0.0 instead of an unassigned IP.","For privileged ports, either use a port >=1024 or run with the necessary privileges/capabilities."],"exampleFix":"// before\nmdbook serve --hostname 192.168.1.99 -p 3000\n\n// after\nmdbook serve --hostname 127.0.0.1 -p 3001","handlingStrategy":"try-catch","validationCode":"// check port availability before launching serve\nuse std::net::TcpListener;\nfn port_free(addr: &str) -> bool {\n    TcpListener::bind(addr).is_ok()\n}\nif !port_free(\"127.0.0.1:3000\") {\n    eprintln!(\"port 3000 in use; pick another with mdbook serve -p <port>\");\n}","typeGuard":null,"tryCatchPattern":"// run mdbook serve as a child process and interpret the panic\nlet status = Command::new(\"mdbook\")\n    .args([\"serve\", \"-p\", &port.to_string()])\n    .status()?;\nif !status.success() {\n    eprintln!(\"serve failed to start (bind error?); try a different port\");\n}","preventionTips":["Reserve a dedicated port for mdbook serve and check it with lsof/ss first.","Terminate stale mdbook serve processes before restarting.","Use ports >= 1024 to avoid permission issues.","Bind to 127.0.0.1 or 0.0.0.0 unless a specific interface is required."],"tags":["network","port-in-use","tcp-bind","serve"],"backgroundTag":"address-already-in-use","analyzedSha":"dc21064fc21d955a0e1f67e65e336883c3e5260b","analyzedAt":"2026-09-01T10:15:12.134Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}