{"record":{"id":"5cca626f09f03747","repo":"ruvnet/ruflo","slug":"maxwriters-must-be-a-positive-integer","errorCode":null,"errorMessage":"maxWriters must be a positive integer","messagePattern":"maxWriters must be a positive integer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/dual-mode/orchestrator.ts","lineNumber":91,"sourceCode":"\n/**\n * Orchestrates parallel execution of Claude Code and Codex workers\n */\nexport class DualModeOrchestrator extends EventEmitter {\n  private config: Required<DualModeConfig>;\n  private workers: Map<string, WorkerResult> = new Map();\n  private processes: Map<string, ChildProcess> = new Map();\n\n  constructor(config: DualModeConfig) {\n    super();\n    if (!Number.isInteger(config.maxConcurrent ?? 4) || (config.maxConcurrent ?? 4) < 1) {\n      throw new Error('maxConcurrent must be a positive integer');\n    }\n    if (!Number.isFinite(config.maxOutputBytes ?? 1_048_576) || (config.maxOutputBytes ?? 1_048_576) < 1) {\n      throw new Error('maxOutputBytes must be positive');\n    }\n    if (!Number.isInteger(config.maxWriters ?? 2) || (config.maxWriters ?? 2) < 1) {\n      throw new Error('maxWriters must be a positive integer');\n    }\n    this.config = {\n      projectPath: config.projectPath,\n      memoryDbPath: path.resolve(\n        config.memoryDbPath\n          ?? process.env.CLAUDE_FLOW_DB_PATH\n          ?? path.join(config.projectPath, '.claude-flow', 'dual-mode-memory.db'),\n      ),\n      maxConcurrent: config.maxConcurrent ?? 4,\n      sharedNamespace: config.sharedNamespace ?? 'collaboration',\n      timeout: config.timeout ?? 300000, // 5 minutes\n      claudeCommand: config.claudeCommand ?? 'claude',\n      codexCommand: config.codexCommand ?? 'codex',\n      maxOutputBytes: config.maxOutputBytes ?? 1_048_576,\n      maxWriters: config.maxWriters ?? 2,\n      worktreeIsolation: config.worktreeIsolation ?? false,\n      dependencyFailure: config.dependencyFailure ?? 'cancel',\n      policyPreflight: config.policyPreflight ?? false,","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/dual-mode/orchestrator.ts#L73-L109","documentation":"The DualModeOrchestrator constructor validates config.maxWriters with Number.isInteger(x ?? 2) && x >= 1. maxWriters bounds how many workers may hold git-writing capability simultaneously (worktree isolation aside, the orchestrator refuses configurations that would let more than this many writers run at once), so it must be a positive integer — 0, negatives, floats, and NaN are rejected.","triggerScenarios":"(1) maxWriters: 0 in a misguided attempt to make the run read-only; (2) NaN from unvalidated env/config strings; (3) fractional values like 1.5 from dividing a worker count; (4) negative numbers from arithmetic on template parameters.","commonSituations":"Derived configs that compute maxWriters = workers.length / branches and round wrongly; security-minded users zeroing the field instead of structuring read-only workers; string-typed values in JSON/TOML configs.","solutions":["Pass a positive integer (e.g. maxWriters: 2) or omit it to accept the default of 2.","For read-only pipelines, mark workers appropriately / give them no writing role — do not zero this field.","Validate external input before construction: `Number.isInteger(n) && n >= 1` else throw with your own clearer message.","Keep maxWriters <= maxConcurrent; a writers cap above total concurrency is meaningless and usually signals a config mistake."],"exampleFix":"// before\nnew DualModeOrchestrator({ projectPath, maxWriters: Number(cfg.max_writers) }); // '' → NaN → throws\n\n// after\nconst w = Number(cfg.max_writers);\nnew DualModeOrchestrator({ projectPath, maxWriters: Number.isInteger(w) && w >= 1 ? w : 2 });","handlingStrategy":"validation","validationCode":"const raw = cfg.max_writers;\nconst maxWriters = Number.isInteger(Number(raw)) && Number(raw) >= 1 ? Number(raw) : 2;\nif (maxWriters > maxConcurrent) {\n  // meaningless cap — tighten it instead of shipping a config smell\n  maxWritersAdjusted = maxConcurrent;\n}\nnew DualModeOrchestrator({ projectPath, maxConcurrent, maxWriters });","typeGuard":null,"tryCatchPattern":"try {\n  new DualModeOrchestrator(config);\n} catch (err) {\n  if (err instanceof Error && err.message === 'maxWriters must be a positive integer') {\n    new DualModeOrchestrator({ ...config, maxWriters: 2 }); // fall back to the default cap\n  } else throw err;\n}","preventionTips":["Validate integer >= 1 for any writer-cap sourced from env/TOML/JSON before construction","Zero is not 'read-only mode' — structure read-only pipelines by worker role instead","Keep maxWriters <= maxConcurrent so the cap is meaningful","Document the cap when sharing configs; other teams inherit it verbatim"],"tags":["dual-mode","orchestrator","config-validation","concurrency","writers"],"backgroundTag":"invalid-config-value","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-01T03:17:15.561Z"}