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

  1. Pass projectRoot on the first call: const daemon = getDaemon(process.cwd())
  2. Or use the higher-level helper: await startDaemon(projectRoot) which creates and starts the daemon in one step
  3. 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
  4. 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

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


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/ef86b0c75e718810. Report an issue: GitHub.