{"record":{"id":"bf57fca66beaee3c","repo":"ruvnet/ruflo","slug":"daemon-config-name-is-already-registered","errorCode":null,"errorMessage":"Daemon '${config.name}' is already registered","messagePattern":"Daemon '(.+?)' is already registered","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/hooks/src/daemons/index.ts","lineNumber":56,"sourceCode":"\n/**\n * Daemon Manager - controls background daemon processes\n */\nexport class DaemonManager {\n  private config: DaemonManagerConfig;\n  private daemons: Map<string, DaemonInstance> = new Map();\n  private restartCounts: Map<string, number> = new Map();\n\n  constructor(config?: Partial<DaemonManagerConfig>) {\n    this.config = { ...DEFAULT_CONFIG, ...config };\n  }\n\n  /**\n   * Register a daemon\n   */\n  register(config: DaemonConfig, task: () => Promise<void>): void {\n    if (this.daemons.has(config.name)) {\n      throw new Error(`Daemon '${config.name}' is already registered`);\n    }\n\n    const state: DaemonState = {\n      name: config.name,\n      status: 'stopped',\n      executionCount: 0,\n      failureCount: 0,\n    };\n\n    this.daemons.set(config.name, { config, state, task });\n  }\n\n  /**\n   * Start a daemon\n   */\n  async start(name: string): Promise<void> {\n    const daemon = this.daemons.get(name);\n    if (!daemon) {","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/hooks/src/daemons/index.ts#L38-L74","documentation":"DaemonManager.register(config, task) throws when a daemon with the same config.name is already present in its internal map. Names are the primary key for start/stop/updateInterval, so double registration is treated as a programming error (usually duplicated setup code) rather than silently replacing the task.","triggerScenarios":"Calling register() twice with the same name — e.g. a module-level init running again during hot module reload, a plugin and the host app both registering 'memory-consolidation', or an init routine retried after partial failure.","commonSituations":"Dev servers with HMR re-executing setup modules; manager initialized in several files instead of a single composition root; retry wrappers around bootstrap code; tests that re-use a module-scoped manager across cases.","solutions":["Guard registration: if (manager.getState(name) === undefined) manager.register(cfg, task) — getState is the public existence probe","Move all daemon registration into one composition root that runs exactly once","For dev/HMR, dispose the old manager (stopAll) or key managers per reload generation before re-registering"],"exampleFix":"// before\nmanager.register({ name: 'metrics', interval: 60_000, enabled: true }, task); // 2nd call throws\n\n// after\nif (manager.getState('metrics') === undefined) {\n  manager.register({ name: 'metrics', interval: 60_000, enabled: true }, task);\n}","handlingStrategy":"validation","validationCode":"// Idempotent registration using the public state probe\nfunction registerOnce(manager: DaemonManager, cfg: DaemonConfig, task: () => Promise<void>): void {\n  if (manager.getState(cfg.name) === undefined) {\n    manager.register(cfg, task);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  manager.register(cfg, task);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('already registered')) {\n    // benign in HMR/retry flows: keep the existing registration\n    return;\n  }\n  throw e;\n}","preventionTips":["Register all daemons in one composition root executed exactly once","For dev HMR, stop and rebuild the manager per reload instead of re-registering into it","Use shared name constants to avoid accidental collisions between modules"],"tags":["daemons","hooks","duplicate-registration","lifecycle"],"backgroundTag":"duplicate-registration","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}