{"record":{"id":"f79edc17fc230573","repo":"ruvnet/ruflo","slug":"maxoutputbytes-must-be-positive","errorCode":null,"errorMessage":"maxOutputBytes must be positive","messagePattern":"maxOutputBytes must be positive","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/dual-mode/orchestrator.ts","lineNumber":88,"sourceCode":"  totalDuration: number;\n  errors: string[];\n}\n\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,","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/dual-mode/orchestrator.ts#L70-L106","documentation":"The DualModeOrchestrator constructor validates config.maxOutputBytes with Number.isFinite(x ?? 1_048_576) && x >= 1. This field caps how much stdout/stderr each spawned worker may produce (default 1 MiB) to bound memory use, so it must be a finite positive number. Unlike maxConcurrent it may be a non-integer float, but zero, negatives, NaN, and Infinity are all rejected.","triggerScenarios":"(1) Setting maxOutputBytes: 0 intending 'no output' (use 1 or redirect instead); (2) NaN from parsing an empty/non-numeric env var or config string; (3) Infinity from Number.MAX_VALUE overflow arithmetic or unbounded 'unlimited' sentinels; (4) negative values from subtractive size math.","commonSituations":"Sizing output caps from free-form env vars; configs migrated from tools where 0 meant unlimited; arithmetic that computes the cap as size - overhead going negative for tiny buffers.","solutions":["Set a finite value >= 1, e.g. maxOutputBytes: 2 * 1024 * 1024, or omit it to accept the 1 MiB default.","Sanitize external input: `const n = Number(raw); if (!Number.isFinite(n) || n < 1) throw new Error('bad maxOutputBytes')`.","Do not use 0 or Infinity as an 'unlimited' marker — the type has no unlimited mode.","If workers genuinely emit more than the cap, raise the number rather than special-casing it."],"exampleFix":"// before\nnew DualModeOrchestrator({ projectPath, maxOutputBytes: Number(env.MAX_OUT) }); // NaN → throws\n\n// after\nconst cap = Number(env.MAX_OUT);\nnew DualModeOrchestrator({\n  projectPath,\n  maxOutputBytes: Number.isFinite(cap) && cap >= 1 ? cap : 1_048_576,\n});","handlingStrategy":"validation","validationCode":"function positiveFinite(raw: unknown, fallback = 1_048_576): number {\n  const n = typeof raw === 'number' ? raw : Number(raw);\n  return Number.isFinite(n) && n >= 1 ? n : fallback;\n}\nnew DualModeOrchestrator({\n  projectPath,\n  maxOutputBytes: positiveFinite(env.MAX_OUTPUT_BYTES), // NaN/0/Infinity → 1 MiB default\n});","typeGuard":null,"tryCatchPattern":"try {\n  new DualModeOrchestrator(config);\n} catch (err) {\n  if (err instanceof Error && err.message === 'maxOutputBytes must be positive') {\n    throw new Error(`maxOutputBytes was ${String(config.maxOutputBytes)} — pass a finite number >= 1 (bytes)`);\n  }\n  throw err;\n}","preventionTips":["Do not use 0 or Infinity as an 'unlimited' marker — the field has no unlimited mode","Sanitize env-var-derived numbers with Number.isFinite before constructing the orchestrator","Watch subtractive arithmetic (total - overhead) that can go negative for small totals","Size caps from observed worker output, not guesses"],"tags":["dual-mode","orchestrator","config-validation","resource-limits","nan"],"backgroundTag":"invalid-config-value","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-01T03:17:15.561Z"}