{"record":{"id":"9229a33236837db9","repo":"ruvnet/ruflo","slug":"writer-worker-id-requires-an-isolated-worktree","errorCode":null,"errorMessage":"writer ${worker.id} requires an isolated worktree","messagePattern":"writer (.+?) requires an isolated worktree","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/dual-mode/orchestrator.ts","lineNumber":439,"sourceCode":"        const remaining = workers.filter((worker) => !placed.has(worker.id)).map((worker) => worker.id);\n        throw new Error(`worker dependency cycle: ${remaining.join(', ')}`);\n      }\n\n      for (const worker of level) {\n        placed.add(worker.id);\n      }\n\n      if (level.length > 0) {\n        levels.push(level);\n      }\n    }\n\n    for (const level of levels) {\n      const writerPaths = new Set<string>();\n      const writers = level.filter((item) => !item.readOnly);\n      for (const worker of writers) {\n        if (this.config.worktreeIsolation && !worker.worktreePath) {\n          throw new Error(`writer ${worker.id} requires an isolated worktree`);\n        }\n        const writerPath = path.resolve(worker.worktreePath ?? this.config.projectPath);\n        if (this.config.worktreeIsolation && writerPaths.has(writerPath)) {\n          throw new Error(`concurrent writers must use distinct worktrees: ${writerPath}`);\n        }\n        writerPaths.add(writerPath);\n      }\n    }\n    return levels;\n  }\n\n  /** Preserve read-only parallelism while independently bounding writers. */\n  private partitionLevel(level: WorkerConfig[]): WorkerConfig[][] {\n    const remaining = [...level];\n    const batches: WorkerConfig[][] = [];\n    while (remaining.length > 0) {\n      const batch: WorkerConfig[] = [];\n      let writers = 0;","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/dual-mode/orchestrator.ts#L421-L457","documentation":"When DualModeOrchestrator is configured with worktreeIsolation: true, every worker that is not marked readOnly must execute in its own git worktree. While scheduling each level the orchestrator checks every writer for a worktreePath and throws for the first writer that has none. The guard exists because concurrent writers sharing one checkout would corrupt shared state (the 'never place two writers in one worktree' invariant).","triggerScenarios":"config.worktreeIsolation = true combined with any worker whose readOnly is false or absent and whose worktreePath is undefined or empty.","commonSituations":"Enabling worktree isolation on an existing swarm config written before the field existed; hand-written worker entries that omit worktreePath; upgrading to a version where isolation became the default; converting read-only workers into writers without adding a worktree.","solutions":["Create a git worktree per writer (git worktree add ../repo-writer-1) and set worker.worktreePath to that directory's absolute path","If the worker only inspects state (tests, analysis, review), mark it readOnly: true — read-only workers may share the project checkout","If concurrent writes to one checkout are genuinely intended and safe, disable worktreeIsolation in the orchestrator config, understanding this removes the write-safety guarantee"],"exampleFix":"// before\nconst config = { projectPath: '/repo', worktreeIsolation: true };\nconst workers = [{ id: 'coder-1', role: 'coder' }]; // writer without a worktree\n\n// after\nconst workers = [{ id: 'coder-1', role: 'coder', worktreePath: '/repo/worktrees/coder-1' }];\n// or, for inspection-only workers:\nconst readers = [{ id: 'reviewer-1', role: 'reviewer', readOnly: true }];","handlingStrategy":"validation","validationCode":"function assertWorktreeIsolationSatisfied(config: OrchestratorConfig, workers: WorkerConfig[]): void {\n  if (!config.worktreeIsolation) return;\n  for (const w of workers) {\n    if (!w.readOnly && !w.worktreePath) {\n      throw new Error(`config error: writer ${w.id} needs worktreePath (or readOnly: true)`);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"Catch around the run and re-check the offending worker id from the message; report it as a configuration defect (missing worktreePath) rather than a runtime failure — do not retry unchanged.","preventionTips":["Provision worktrees in the same loop that builds worker configs so a writer without a worktree cannot be constructed","Mark inspection-only workers readOnly explicitly","Add a config-schema test that fails CI when worktreeIsolation is on and any writer lacks worktreePath"],"tags":["orchestration","git-worktree","concurrency","configuration","writers"],"backgroundTag":"missing-required-config-field","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-01T03:17:15.561Z"}