{"record":{"id":"ed5a957483c3f05c","repo":"a-b-street/abstreet","slug":"server-error","errorCode":null,"errorMessage":"Server error: {}","messagePattern":"Server error: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"headless/src/main.rs","lineNumber":104,"sourceCode":"        let mut load = LOAD.write().unwrap();\n        load.rng_seed = args.rng_seed;\n        load.opts = args.opts;\n        if let Some(path) = args.scenario {\n            load.scenario = path;\n        }\n\n        let (map, sim) = load.setup(&mut Timer::new(\"setup headless\"));\n        *MAP.write().unwrap() = map;\n        *SIM.write().unwrap() = sim;\n    }\n\n    let addr = std::net::SocketAddr::from((args.ip, args.port));\n    info!(\"Listening on http://{}\", addr);\n    let serve_future = Server::bind(&addr).serve(hyper::service::make_service_fn(|_| async {\n        Ok::<_, hyper::Error>(hyper::service::service_fn(serve_req))\n    }));\n    if let Err(err) = serve_future.await {\n        panic!(\"Server error: {}\", err);\n    }\n}\n\nasync fn serve_req(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {\n    let path = req.uri().path().to_string();\n    // Url::parse needs an absolute URL\n    let params: HashMap<String, String> =\n        url::Url::parse(&format!(\"http://localhost{}\", req.uri()))\n            .unwrap()\n            .query_pairs()\n            .map(|(k, v)| (k.to_string(), v.to_string()))\n            .collect();\n    let body = hyper::body::to_bytes(req).await?.to_vec();\n    info!(\"Handling {}\", path);\n    Ok(\n        match handle_command(\n            &path,\n            &params,","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/headless/src/main.rs#L86-L122","documentation":"headless's main binds a hyper TCP server on the configured socket address and awaits serve_future. If the server future terminates with a hyper::Error (typically a bind failure like the port already being in use, or a fatal accept/IO error), main panics with \"Server error: {err}\". This is a fatal startup/runtime abort for the headless map server.","triggerScenarios":"Running the headless binary when args.port is already bound by another process, the address isn't available on the host, the port is privileged (<1024) without permissions, or hyper hits a fatal IO error while serving.","commonSituations":"Starting two instances of the headless server on the same port; a stale/zombie process holding the port; Docker/K8s port mapping conflicts; running as non-root on a privileged port.","solutions":["Choose a different --port (or free the port: find and kill the process bound to it, e.g. `lsof -i :PORT`).","Bind to 0.0.0.0 instead of a specific unavailable IP if running in a container.","Use an unprivileged port (>1024) or run with appropriate permissions.","Wrap the serve future with graceful error handling/log instead of panicking if the failure should be survivable."],"exampleFix":"// before\nif let Err(err) = serve_future.await {\n    panic!(\"Server error: {}\", err);\n}\n// after\nif let Err(err) = serve_future.await {\n    eprintln!(\"server shut down: {}\", err);\n    std::process::exit(1);\n}","handlingStrategy":"validation","validationCode":"use std::net::TcpListener;\n// before starting the server, verify the port is free:\nif TcpListener::bind(addr).is_err() {\n    eprintln!(\"port {} already in use; pick another\", addr.port());\n    std::process::exit(1);\n}","typeGuard":null,"tryCatchPattern":"// Panics uncatchably; wrap startup in your own bind probe or use\n// TcpListener::bind + Server::from_tcp to get a Result.","preventionTips":["Use unprivileged, configurable ports (>1024) and document them.","Add readiness/liveness checks that fail fast on port conflicts.","In containers, align published ports with the bound address."],"tags":["panic","hyper","server","port-bind","network"],"backgroundTag":"address-already-in-use","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}