{"record":{"id":"3e6a52364928c0ab","repo":"deepseek-ai/deepseek-harness","slug":"approval-request-outside-an-open-turn-the-appro","errorCode":null,"errorMessage":"approval.request() outside an open turn: the approval/asked + approval/decided audit pair must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). Ask from inside the turn that needs the decision.","messagePattern":"approval\\.request\\(\\) outside an open turn: the approval/asked \\+ approval/decided audit pair must be turn-enclosed \\(a bare event between turns is crash-tail garbage on reload\\)\\. Ask from inside the turn that needs the decision\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/interaction/user-approval/src/index.ts","lineNumber":260,"sourceCode":"   * The request requires an open turn because the audit pair must be enclosed\n   * by the durable log's commit/replay boundary; an idle ask rejects before\n   * appending anything. The answerer phase always produces an outcome: an\n   * aborted signal yields `'cancelled'`, a missing or throwing answerer yields\n   * `'unavailable'` (fail closed), and a rogue non-vocabulary return value is\n   * normalized to `'unavailable'`. A failure that prevents either audit append\n   * from committing still rejects because returning an unlogged decision would\n   * violate the pair. Session contains post-commit observer failures, so an\n   * authoritative append cannot reject the request or suppress its matching\n   * audit event.\n   * @param req - the pending decision (agent, tool identity, reason, signal).\n   * @returns the closed outcome; `'allowed-once'` is the only grant.\n   * @throws when no turn is open or either audit event fails before the session\n   *   append commit point.\n   */\n  async request(req: ApprovalRequest): Promise<ApprovalOutcome> {\n    const session = req.agent.session\n    if (!hasOpenTurn(session.events)) {\n      throw new Error(\n        'approval.request() outside an open turn: the approval/asked + approval/decided audit pair '\n        + 'must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). '\n        + 'Ask from inside the turn that needs the decision.',\n      )\n    }\n    const id = ApprovalRequestId(randomUUID())\n    session.append('approval/asked', {\n      id,\n      toolName: req.toolName,\n      ...req.callId !== undefined ? { callId: req.callId } : {},\n      ...req.reason !== undefined ? { reason: req.reason } : {},\n    })\n    const outcome = await this.decide(req, session)\n    session.append('approval/decided', { id, outcome })\n    return outcome\n  }\n\n  /**","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/interaction/user-approval/src/index.ts#L242-L278","documentation":"Error \"approval.request() outside an open turn: the approval/asked + approval/decided audit pair must be turn-enclosed (a bare event between turns is crash-tail garbage on reload). Ask from inside the turn that needs the decision.\" thrown in deepseek-ai/deepseek-harness.","triggerScenarios":"Thrown at packages/interaction/user-approval/src/index.ts:260 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Call approval.request() from inside the turn that needs the decision so the approval/asked and approval/decided events stay turn-enclosed."],"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"}