{"record":{"id":"83c86b64092be16e","repo":"ruvnet/ruflo","slug":"meta-proxy-is-already-running-pid-pid-stop-i","errorCode":null,"errorMessage":"meta-proxy is already running (pid ${pid}). Stop it first with: ruflo proxy stop","messagePattern":"meta-proxy is already running \\(pid (.+?)\\)\\. Stop it first with: ruflo proxy stop","errorType":"exception","errorClass":"ProxyAlreadyRunningError","httpStatus":null,"severity":"warning","filePath":"v3/@claude-flow/cli/src/proxy/lifecycle.ts","lineNumber":177,"sourceCode":"    fs.unlinkSync(proxyLockFilePath());\n  } catch {\n    /* ignore */\n  }\n}\n\n/**\n * Foreground start (ADR-307 default) — blocks the caller until the process\n * exits or is interrupted. `stdio: 'inherit'` passes the proxy's own output\n * straight through to the terminal; signals (Ctrl+C) propagate naturally to\n * the child, no manual forwarding needed.\n */\nexport async function startForeground(supervised = false): Promise<never> {\n  const bin = requireBinary();\n  const status = getProxyStatus();\n  // In service mode startBackground has already written this supervisor's\n  // PID. Treating it as a competing proxy makes the supervisor immediately\n  // exit before it can spawn meta-proxy.\n  if (!supervised && status.running && status.pid) throw new ProxyAlreadyRunningError(status.pid);\n  if (status.stalePidFile) clearStalePidFile();\n\n  const child = spawn(bin, [], { stdio: 'inherit', windowsHide: false });\n  if (!supervised && child.pid) writePidFile(child.pid);\n\n  const cleanup = () => clearStalePidFile();\n  process.on('exit', cleanup);\n  if (supervised) {\n    const forwardSignal = (signal: NodeJS.Signals) => {\n      if (!child.killed) child.kill(signal);\n    };\n    process.once('SIGTERM', () => forwardSignal('SIGTERM'));\n    process.once('SIGINT', () => forwardSignal('SIGINT'));\n  }\n\n  await new Promise<void>((resolve) => {\n    child.on('exit', () => {\n      cleanup();","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/proxy/lifecycle.ts#L159-L195","documentation":"startForeground() refuses to start a second meta-proxy: it reads the PID file and probes it with signal 0 (process.kill(pid, 0)); if a live process answers, ProxyAlreadyRunningError is thrown carrying the running PID. The check is skipped in supervised mode because there the supervisor's own PID was deliberately written by startBackground.","triggerScenarios":"`ruflo proxy start` (foreground, not --service) while a previous meta-proxy still runs; double-invoking start in two terminals; a `--service` instance started earlier still holding the recorded PID.","commonSituations":"A terminal left with the proxy in the foreground; forgetting an earlier `ruflo proxy start --service` is still alive; a second automation script starting the proxy unconditionally.","solutions":["Stop the existing instance: `ruflo proxy stop`, then start again","Run `ruflo proxy status` and inspect the live PID — you may just want to leave it running","If the recorded PID belongs to an unrelated recycled process (pid reuse after reboot), follow the status output's stalePidFile hint to clear the stale pid file and retry"],"exampleFix":"# before\nruflo proxy start   # already running (pid 1234)\n# after\nruflo proxy stop && ruflo proxy start","handlingStrategy":"try-catch","validationCode":"import { getProxyStatus } from '@claude-flow/cli/.../proxy/lifecycle.js';\nconst status = getProxyStatus();\nif (!status.running) {\n  await startForeground();\n} else {\n  console.log(`already running, pid ${status.pid}`);\n}","typeGuard":"const isAlreadyRunning = (e: unknown): e is Error & { pid: number } =>\n  e instanceof Error && e.name === 'ProxyAlreadyRunningError';","tryCatchPattern":"try {\n  await startForeground();\n} catch (e) {\n  if (isAlreadyRunning(e)) return; // idempotent start: already running is success\n  throw e;\n}","preventionTips":["Check `ruflo proxy status` before start in scripts","Treat ProxyAlreadyRunningError as success in idempotent automation","Remember supervised mode intentionally skips this check — don't mix foreground and supervised modes blindly"],"tags":["proxy","lifecycle","single-instance","pid-file"],"backgroundTag":"process-already-running","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}