{"record":{"id":"5a0fdc1a6bdf08bb","repo":"decolua/9router","slug":"bridge-not-running-name","errorCode":null,"errorMessage":"Bridge not running: ${name}","messagePattern":"Bridge not running: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lib/mcp/stdioSseBridge.js","lineNumber":174,"sourceCode":"  // No sessions left → kill child to avoid idle orphan process leak.\n  if (entry.sessions.size === 0) {\n    try { entry.proc.kill(); } catch { /* ignore */ }\n    getStore().delete(name);\n  }\n}\n\n// Kill all spawned MCP children — called on app shutdown to prevent orphans.\nfunction killAllBridges() {\n  const store = getStore();\n  for (const [name, entry] of store) {\n    try { entry.proc.kill(); } catch { /* ignore */ }\n    store.delete(name);\n  }\n}\n\nfunction sendToChild(name, jsonRpc) {\n  const entry = getStore().get(name);\n  if (!entry?.proc?.stdin?.writable) throw new Error(`Bridge not running: ${name}`);\n  entry.proc.stdin.write(`${JSON.stringify(jsonRpc)}\\n`);\n}\n\nfunction isRunning(name) {\n  const entry = getStore().get(name);\n  return !!(entry?.proc && !entry.proc.killed && entry.proc.exitCode === null);\n}\n\nmodule.exports = { getOrSpawn, registerSession, unregisterSession, sendToChild, isRunning, findPlugin, killAllBridges };\n","sourceCodeStart":156,"sourceCodeEnd":184,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/mcp/stdioSseBridge.js#L156-L184","documentation":"sendToChild writes a JSON-RPC message to a spawned stdio bridge child's stdin. It throws if no live entry with a writable stdin exists for that name — i.e. the child process died, was never spawned, or was just cleaned up.","triggerScenarios":"POSTing a JSON-RPC message to the bridge after the plugin process exited (crash, was killed, command failed to launch), or sending to a name that was never getOrSpawn'ed, or racing a cleanup that deleted the store entry.","commonSituations":"MCP server binary crashed mid-session (e.g. npx failed, OOM-killed child); session idle timeout reaped the child while the client still holds it; sending the very first request without an initialize that would have spawned the process.","solutions":["Re-issue the request: entry() getOrSpawn will respawn a dead child automatically if the plugin is registered.","Check the child's stderr/logs for why the process died (missing binary, npx network failure, crash) and fix the root cause.","Verify the plugin command runs standalone (e.g. `npx -y <pkg> --help`) — a bad command or missing dependency makes the child exit immediately.","Treat the error as a stale session on the client side: re-initialize the MCP session to get a fresh bridge."],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"import { isRunning } from \"@/lib/mcp/stdioSseBridge\"; // or equivalent check\nif (!isRunning(name)) {\n  getOrSpawn(name); // respawn before sending\n}\nsendToChild(name, jsonRpc);","typeGuard":null,"tryCatchPattern":"try {\n  sendToChild(name, jsonRpc);\n} catch (err) {\n  if (err.message.startsWith(\"Bridge not running:\")) {\n    getOrSpawn(name);        // respawn the dead child\n    sendToChild(name, jsonRpc); // retry once\n  } else throw err;\n}","preventionTips":["Check isRunning(name) before writing, or wrap send+respawn+retry in one helper.","Inspect child stderr output to catch crash loops (bad command, missing npx package).","Treat bridge children as ephemeral: any send can fail after a crash; re-initialize the MCP session on failure.","Avoid long idle sessions without heartbeats — the child may be reaped."],"tags":["mcp","ipc","process-lifecycle"],"backgroundTag":"bridge-not-running","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}