ruvnet/ruflo · error · Error
Daemon not initialized. Provide projectRoot on first call.
Error message
Daemon not initialized. Provide projectRoot on first call.
What it means
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.
Source
Thrown at v3/@claude-flow/cli/src/services/worker-daemon.ts:2118
appendFileSync(logFile, logMessage + '\n');
} catch {
// Ignore log write errors
}
}
}
// Singleton instance for global access
let daemonInstance: WorkerDaemon | null = null;
/**
* Get or create daemon instance
*/
export function getDaemon(projectRoot?: string, config?: Partial<DaemonConfig>): WorkerDaemon {
if (!daemonInstance && projectRoot) {
daemonInstance = new WorkerDaemon(projectRoot, config);
}
if (!daemonInstance) {
throw new Error('Daemon not initialized. Provide projectRoot on first call.');
}
return daemonInstance;
}
/**
* Start daemon (for use in session-start hook)
*/
export async function startDaemon(projectRoot: string, config?: Partial<DaemonConfig>): Promise<WorkerDaemon> {
const daemon = getDaemon(projectRoot, config);
await daemon.start();
return daemon;
}
/**
* Stop daemon
*/
export async function stopDaemon(): Promise<void> {
if (daemonInstance) {View on GitHub (pinned to fa13ee4ad6)
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
Example fix
// before const daemon = getDaemon(); // throws if nothing created it yet await daemon.status(); // after const daemon = getDaemon(process.cwd()); // first call provides projectRoot await daemon.status();
Defensive patterns
Strategy: validation
Validate before calling
// Always anchor singleton creation on a known projectRoot: const projectRoot = process.cwd(); const daemon = getDaemon(projectRoot); // safe: first call provides the root await daemon.status();
Try / catch
function getDaemonIfRunning(projectRoot: string): WorkerDaemon | null {
try {
return getDaemon(projectRoot);
} catch (e) {
if (/Daemon not initialized/.test(String(e?.message))) return null; // not started yet
throw e;
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ruvLLM bridge not initialized. Call with config first.
- Unknown worker type: ${type}
- Worker ${this.id} not initialized. Call initialize() first.
- MCP initialization failed: ${initResponse.error.message}
- ${label} contains null bytes
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/ef86b0c75e718810.
Report an issue: GitHub.