{"record":{"id":"ef86b0c75e718810","repo":"ruvnet/ruflo","slug":"daemon-not-initialized-provide-projectroot-on-fir","errorCode":null,"errorMessage":"Daemon not initialized. Provide projectRoot on first call.","messagePattern":"Daemon not initialized\\. Provide projectRoot on first call\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/worker-daemon.ts","lineNumber":2118,"sourceCode":"      appendFileSync(logFile, logMessage + '\\n');\n    } catch {\n      // Ignore log write errors\n    }\n  }\n}\n\n// Singleton instance for global access\nlet daemonInstance: WorkerDaemon | null = null;\n\n/**\n * Get or create daemon instance\n */\nexport function getDaemon(projectRoot?: string, config?: Partial<DaemonConfig>): WorkerDaemon {\n  if (!daemonInstance && projectRoot) {\n    daemonInstance = new WorkerDaemon(projectRoot, config);\n  }\n  if (!daemonInstance) {\n    throw new Error('Daemon not initialized. Provide projectRoot on first call.');\n  }\n  return daemonInstance;\n}\n\n/**\n * Start daemon (for use in session-start hook)\n */\nexport async function startDaemon(projectRoot: string, config?: Partial<DaemonConfig>): Promise<WorkerDaemon> {\n  const daemon = getDaemon(projectRoot, config);\n  await daemon.start();\n  return daemon;\n}\n\n/**\n * Stop daemon\n */\nexport async function stopDaemon(): Promise<void> {\n  if (daemonInstance) {","sourceCodeStart":2100,"sourceCodeEnd":2136,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/services/worker-daemon.ts#L2100-L2136","documentation":"getDaemon() is a lazy singleton accessor: it only constructs a WorkerDaemon when a projectRoot is supplied (or when an instance already exists). Calling getDaemon() with no argument before any prior getDaemon(projectRoot)/startDaemon call means there is nothing to return, so it throws. The message states the contract directly: the first call must carry projectRoot.","triggerScenarios":"Calling getDaemon() (worker-daemon.ts:2118) as the very first daemon access in the process; calling stop/status helpers that internally use getDaemon() without arguments before the session-start hook created the daemon; multiple entry points where one assumes another already initialized the singleton.","commonSituations":"A session-end or cleanup hook that runs getDaemon() when session-start never ran (e.g. skipped hook, crashed startup); unit tests that grab the singleton directly instead of constructing WorkerDaemon or calling startDaemon; refactors that reordered startup so a status query runs before daemon creation.","solutions":["Pass projectRoot on the first call: const daemon = getDaemon(process.cwd())","Or use the higher-level helper: await startDaemon(projectRoot) which creates and starts the daemon in one step","If you only want the daemon when it already exists, guard with a try/catch or track whether session-start ran before calling getDaemon() bare","Ensure the session-start hook (which calls startDaemon) has executed before any code path that queries the singleton"],"exampleFix":"// before\nconst daemon = getDaemon(); // throws if nothing created it yet\nawait daemon.status();\n\n// after\nconst daemon = getDaemon(process.cwd()); // first call provides projectRoot\nawait daemon.status();","handlingStrategy":"validation","validationCode":"// Always anchor singleton creation on a known projectRoot:\nconst projectRoot = process.cwd();\nconst daemon = getDaemon(projectRoot); // safe: first call provides the root\nawait daemon.status();","typeGuard":null,"tryCatchPattern":"function getDaemonIfRunning(projectRoot: string): WorkerDaemon | null {\n  try {\n    return getDaemon(projectRoot);\n  } catch (e) {\n    if (/Daemon not initialized/.test(String(e?.message))) return null; // not started yet\n    throw e;\n  }\n}","preventionTips":["Use startDaemon(projectRoot) as the single entry point — it creates and starts the daemon in one call","Never call the argument-less getDaemon() in cleanup/teardown paths; those run even when startup was skipped","In multi-entry projects, make the session-start hook the only place that creates the singleton, and have all other paths tolerate its absence"],"tags":["daemon","singleton","initialization","worker"],"backgroundTag":"component-not-initialized","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}