{"record":{"id":"14007fefbf261513","repo":"xai-org/grok-build","slug":"another-leader-already-holds-the-lock-at","errorCode":null,"errorMessage":"Another leader already holds the lock at {}","messagePattern":"Another leader already holds the lock at (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"crates/codegen/xai-grok-shell/src/agent/app.rs","lineNumber":791,"sourceCode":"    });\n    let mut agent_config = agent_config.clone();\n    agent_config.mode = crate::agent::config::AgentMode::Leader;\n    let ws_url = &agent_config.grok_com_config.grok_ws_url;\n    let mut lock = LeaderLock::new(ws_url);\n    let socket_path = lock.socket_path().clone();\n    match lock.try_acquire() {\n        Ok(true) => {\n            lock.write_pid()?;\n            debug!(\"Acquired leader lock, proceeding as leader\");\n        }\n        Ok(false) => {\n            if crate::leader::listener_is_ready(&socket_path) {\n                info!(\n                    \"Another process holds the leader lock with a bound socket ({}). \\\n                     Exiting so the client adopts it.\",\n                    socket_path.display()\n                );\n                return Err(anyhow::anyhow!(\n                    \"Another leader already holds the lock at {}\",\n                    socket_path.display()\n                ));\n            }\n            match lock.acquire_reopen_timeout(LEADER_ACQUIRE_TIMEOUT).await {\n                Ok(()) => {\n                    lock.write_pid()?;\n                    debug!(\"Acquired leader lock after bounded wait, proceeding as leader\");\n                }\n                Err(LockError::Timeout(_)) => {\n                    info!(\n                        \"Timed out waiting for the leader lock ({}). Exiting so the \\\n                         client adopts whoever won it.\",\n                        socket_path.display()\n                    );\n                    return Err(anyhow::anyhow!(\n                        \"Timed out acquiring leader lock at {}\",\n                        socket_path.display()","sourceCodeStart":773,"sourceCodeEnd":809,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/agent/app.rs#L773-L809","documentation":"run_leader detected, via crate::leader::listener_is_ready, that another process already holds the leader lock with a bound IPC socket at the given path. This is the single-instance guard of the agent: instead of fighting for leadership, this process logs and returns an error so the caller exits and the client adopts the existing leader. It is an expected, by-design outcome of launching a second agent instance, not a fault.","triggerScenarios":"Calling run_leader (via run_agent_command) when the socket_path already has a live listener bound by another agent process; specifically the check `crate::leader::listener_is_ready(&socket_path)` returns true before lock.acquire_reopen_timeout is attempted.","commonSituations":"Launching the agent twice (double shell startup, autostart entry plus manual run); a previous leader is still running normally; running an agent in multiple terminal tabs against the same XDG runtime dir.","solutions":["Do nothing to fix — exit gracefully; the running leader is healthy and the client will adopt it.","If you genuinely need a second independent agent, change the socket/lock path (e.g. a different XDG_RUNTIME_DIR or profile) so each instance has its own socket_path.","If you believe no other agent is running, verify with `ss -xl | grep <socket-name>` or `lsof <socket_path>` to find the process holding the socket, then stop it.","Remove a stale-but-live socket only after confirming the owner process is defunct."],"exampleFix":"// before: treating second launch as a crash\nrun_agent_command(...).await?;\n\n// after: treat this specific error as a graceful exit\nif let Err(e) = run_agent_command(...).await {\n    if e.to_string().starts_with(\"Another leader already holds the lock\") {\n        info!(\"leader already running; exiting so client adopts it\");\n        return Ok(());\n    }\n    return Err(e);\n}","handlingStrategy":"fallback","validationCode":"let socket_path = agent_socket_path();\nif crate::leader::listener_is_ready(&socket_path) {\n    info!(\"leader already running at {}\", socket_path.display());\n    return Ok(ExitCode::from(0)); // adopt existing leader\n}","typeGuard":"fn is_already_leader_err(e: &anyhow::Error) -> bool {\n    e.to_string().starts_with(\"Another leader already holds the lock\")\n}","tryCatchPattern":"match run_agent_command(...).await {\n    Err(e) if is_already_leader_err(&e) => Ok(()), // expected: adopt existing leader\n    other => other,\n}","preventionTips":["Treat this error as success in launchers/autostart scripts so double launches do not report failures.","Never delete the socket file while a leader may be alive — probe listener_is_ready first.","Give each profile/user its own socket path to avoid intentional cross-instance collisions."],"tags":["ipc","single-instance","leader-election","unix-socket"],"backgroundTag":"leader-lock-already-held","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}