{"record":{"id":"4c1026d1b4730e80","repo":"deepseek-ai/deepseek-harness","slug":"tool-jobs-maxconsecutivewakes-wakebudget-mus","errorCode":null,"errorMessage":"tool-jobs: maxConsecutiveWakes (${wakeBudget}) must be a whole number of turns","messagePattern":"tool-jobs: maxConsecutiveWakes \\((.+?)\\) must be a whole number of turns","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jobs/tool-jobs/src/index.ts","lineNumber":221,"sourceCode":"}\n\nexport function apply(ctx: Context, config: Config): void {\n  const waitDefault = config.waitTimeoutMs ?? 30_000\n  const waitCap = config.maxWaitTimeoutMs ?? 600_000\n  const delivery = config.completionDelivery ?? 'wakeup'\n  const wakeBudget = config.maxConsecutiveWakes ?? 3\n\n  // Turns this plugin opened on each owner since that owner last consumed\n  // human input. Keyed by the exact Agent, so a same-session replacement\n  // starts with a full budget.\n  const spentWakes = new WeakMap<Agent, number>()\n  if (waitDefault > waitCap) {\n    throw new Error(`tool-jobs: waitTimeoutMs (${waitDefault}) exceeds maxWaitTimeoutMs (${waitCap})`)\n  }\n  // A budget is a count of turns. `Infinity` would leave the runaway chain this\n  // field exists to bound unbounded, and a fraction never names a turn at all.\n  if (!Number.isSafeInteger(wakeBudget)) {\n    throw new Error(`tool-jobs: maxConsecutiveWakes (${wakeBudget}) must be a whole number of turns`)\n  }\n  // Nothing spends the budget under quiet delivery, so nothing needs to refill it.\n  if (delivery === 'wakeup') {\n    ctx.on('agent/inbox/claimed', ({ agent, message }) => {\n      // Claiming is the point the human's input actually enters a step; a notice\n      // this plugin itself queued must not refill the budget it just spent.\n      if (message.source.kind === 'user') spentWakes.delete(agent)\n    })\n  }\n\n  const outputLimits = new WeakMap<ToolExecution, number>()\n  ctx.on('tools/pre-execute', (exec, next) => {\n    const maxBytes = visibleOutputLimit(ctx, exec)\n    if (maxBytes !== undefined) outputLimits.set(exec, maxBytes)\n    return next()\n  }, { prepend: true })\n  const finalizeTaskContent: NonNullable<ToolDefinition['finalizeContent']> = (exec, result) => {\n    const maxBytes = outputLimits.get(exec) ?? visibleOutputLimit(ctx, exec)","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/jobs/tool-jobs/src/index.ts#L203-L239","documentation":"Error \"tool-jobs: maxConsecutiveWakes (${wakeBudget}) must be a whole number of turns\" thrown in deepseek-ai/deepseek-harness.","triggerScenarios":"Thrown at packages/jobs/tool-jobs/src/index.ts:221 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Set maxConsecutiveWakes to a whole number of turns."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"b150a551b8d465e31e418e1b2eaf5e79bbb7d28e","analyzedAt":"2026-08-24T18:12:29.105Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}