ruvnet/ruflo · error

Daemon '${name}' is disabled

Error message

Daemon '${name}' is disabled

What it means

DaemonManager.start(name) throws this when the daemon exists and is not running, but its registered config has enabled: false. Disabled daemons refuse to start as a deliberate control — you must explicitly re-enable via manager.enable(name) (or register with enabled: true) before starting.

Source

Thrown at v3/@claude-flow/hooks/src/daemons/index.ts:83

    this.daemons.set(config.name, { config, state, task });
  }

  /**
   * Start a daemon
   */
  async start(name: string): Promise<void> {
    const daemon = this.daemons.get(name);
    if (!daemon) {
      throw new Error(`Daemon '${name}' not found`);
    }

    if (daemon.state.status === 'running') {
      return; // Already running
    }

    if (!daemon.config.enabled) {
      throw new Error(`Daemon '${name}' is disabled`);
    }

    daemon.state.status = 'starting';
    daemon.state.startedAt = new Date();

    try {
      // Start interval timer
      daemon.timer = setInterval(async () => {
        await this.executeDaemonTask(name);
      }, daemon.config.interval);

      daemon.state.status = 'running';
      daemon.state.pid = process.pid; // Use current process for in-process daemons

      // Run initial execution
      await this.executeDaemonTask(name);
    } catch (error) {
      daemon.state.status = 'error';

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Call manager.enable(name) before manager.start(name) for daemons registered disabled
  2. Or register with enabled: true if the daemon should start with the manager
  3. Centralize the enable+start sequence in one startDaemon(name) helper so they cannot diverge

Example fix

// before
manager.register({ name: 'metrics', interval: 60_000, enabled: false }, task);
await manager.start('metrics'); // throws: disabled

// after
manager.enable('metrics');
await manager.start('metrics');
Defensive patterns

Strategy: validation

Validate before calling

// Explicit enable+start keeps intent clear
function startDaemon(manager: DaemonManager, name: string): Promise<void> {
  if (manager.getState(name) === undefined) {
    throw new Error(`daemon '${name}' not registered`);
  }
  manager.enable(name); // no-op style guard before start
  return manager.start(name);
}

Try / catch

try {
  await manager.start(name);
} catch (e) {
  if (e instanceof Error && e.message.includes('is disabled')) {
    manager.enable(name);
    await manager.start(name);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Registering a daemon with { name, interval, enabled: false } (e.g. an opt-in daemon) and later calling start(name) without calling enable(name) first; or calling disable(name) at runtime and then start(name) again.

Common situations: Daemons registered disabled-by-default for feature-flag rollout where the flag flips but enable() is never invoked; shutdown logic that disables daemons and restart logic that only calls start(); config-driven enabled fields defaulting to false when omitted from partial config objects.

Related errors


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