{"record":{"id":"94d5a3c706ebcda9","repo":"BoundaryML/baml","slug":"could-not-bind-playground-port-port-e-another-process-may-be","errorCode":null,"errorMessage":"Could not bind playground port {port}: {e}. Another process may be using it; pass a different --port or omit it to auto-pick from 4265.","messagePattern":"Could not bind playground port (.+?): (.+?)\\. Another process may be using it; pass a different --port or omit it to auto-pick from 4265\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"baml_language/crates/baml_lsp_server/src/playground_server.rs","lineNumber":424,"sourceCode":"}\n\n/// Resolve the given env var names against `lookup`, keeping only those set.\n/// Pure so tests never have to mutate the process environment.\nfn collect_referenced_env_vars(\n    names: &[String],\n    lookup: impl Fn(&str) -> Option<String>,\n) -> std::collections::HashMap<String, String> {\n    names\n        .iter()\n        .filter_map(|n| lookup(n).map(|v| (n.clone(), v)))\n        .collect()\n}\n\n/// Bind exactly `port` on loopback, with an actionable error when taken.\npub async fn bind_exact_port(port: u16) -> anyhow::Result<TcpListener> {\n    let addr = SocketAddr::from(([127, 0, 0, 1], port));\n    TcpListener::bind(addr).await.map_err(|e| {\n        anyhow::anyhow!(\n            \"Could not bind playground port {port}: {e}. Another process may be \\\n             using it; pass a different --port or omit it to auto-pick from 4265.\"\n        )\n    })\n}\n\n// ---------------------------------------------------------------------------\n// Shared state for Axum handlers\n// ---------------------------------------------------------------------------\n\n/// Per-file mirror of the content the BROWSER currently has (set from\n/// didOpen/didChange). The disk watcher consults it to avoid echoing the\n/// browser's own write-throughs back as \"external\" changes — only content that\n/// differs from the mirror is pushed to the browser. Shared between the `/api/lsp`\n/// bridge (writer) and the disk watcher (reader). Keyed by canonical path.\npub type DocMirror = Arc<std::sync::Mutex<std::collections::HashMap<PathBuf, String>>>;\n\n/// Custom LSP notification used to push external on-disk edits to the browser","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/baml_lsp_server/src/playground_server.rs#L406-L442","documentation":"bind_exact_port binds exactly the user-requested port on 127.0.0.1 and converts any bind failure into an actionable anyhow error. Unlike pick_port it never falls back to another port, because the user explicitly asked for this one.","triggerScenarios":"Calling bind_exact_port(port) when another process already holds that port (AddrInUse), or when binding fails for OS reasons (permissions, invalid address); typically after the user passed --port N to the playground.","commonSituations":"A previous playground/LSP session still running on 4265; another dev server (Vite, webpack) on the chosen port; Docker container publishing the same port; starting two LSP clients concurrently with the same explicit --port.","solutions":["Pick a different port with --port N.","Omit --port entirely so pick_port auto-selects from 4265 upward.","Stop the conflicting process (lsof -i :<port> then kill it).","Wait and retry if the previous session is shutting down."],"exampleFix":"// before\nbaml lsp --port 4265   // 4265 already used by old session\n\n// after\nbaml lsp --port 4280   // or omit --port to auto-pick","handlingStrategy":"fallback","validationCode":"let free = std::net::TcpListener::bind((\"127.0.0.1\", requested_port)).is_ok();\nif !free { eprintln!(\"port {requested_port} in use; will auto-pick\"); }","typeGuard":null,"tryCatchPattern":"match bind_exact_port(port).await {\n    Ok(listener) => serve(listener),\n    Err(e) if e.to_string().contains(\"Could not bind playground port\") => {\n        let (listener, p) = pick_port(4265, 100).await?;\n        serve(listener)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Omit --port unless you specifically need a fixed port","Check the port is free before launching (lsof -i :<port>)","Shut down previous playground sessions before restarting"],"tags":["rust","network","port-conflict","tcp"],"backgroundTag":"address-already-in-use","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}