{"record":{"id":"f43877710f51c929","repo":"rohitg00/ai-engineering-from-scratch","slug":"resume-from-awaiting-tool-requires-a-payload","errorCode":null,"errorMessage":"resume from AWAITING_TOOL requires a payload","messagePattern":"resume from AWAITING_TOOL requires a payload","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"phases/19-capstone-projects/20-agent-harness-loop-contract/code/main.py","lineNumber":239,"sourceCode":"\n    def resume(self, payload: dict | None = None) -> PullRequest | SessionResult:\n        if self.state == State.IDLE and self._reason.startswith(\"budget_exceeded\"):\n            self.budget.turns = 0\n            self.budget.tool_calls = 0\n            self.budget.started_at = time.time()\n            self._reason = \"\"\n            prev = self._prev_state\n            self._prev_state = None\n            if not self._plan:\n                return self._begin_plan()\n            if prev == State.EXECUTING:\n                self.state = State.EXECUTING\n            else:\n                self.state = State.REFLECTING\n            return self._step()\n        if self.state == State.AWAITING_TOOL:\n            if payload is None:\n                raise ValueError(\"resume from AWAITING_TOOL requires a payload\")\n            current = self._plan[self._cursor]\n            if \"error\" in payload:\n                current.error = str(payload[\"error\"])\n                self._emit(\"tool.error\", {\"step\": current.id, \"error\": current.error})\n                self.hooks.fire(\"on_error\", {\"step\": current, \"error\": current.error})\n            else:\n                current.result = payload.get(\"result\")\n                self._emit(\"tool.result\", {\"step\": current.id, \"result\": current.result})\n            self.hooks.fire(\"after_tool_call\", {\"step\": current})\n            self._transition(State.REFLECTING)\n            return self._step()\n        raise RuntimeError(f\"resume() unsupported from state {self.state.value}\")\n\n    def _begin_plan(self) -> PullRequest | SessionResult:\n        self._transition(State.PLANNING)\n        self.hooks.fire(\"before_plan\", {\"goal\": self._goal, \"history\": list(self._history)})\n        draft = self._planner(self._goal, list(self._history))\n        self._emit(\"plan.draft\", {\"steps\": [s.description for s in draft]})","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/rohitg00/ai-engineering-from-scratch/blob/39ea8a1c6d0b61f071226eff7ede4d4105fed820/phases/19-capstone-projects/20-agent-harness-loop-contract/code/main.py#L221-L257","documentation":"Payload precondition on Harness.resume: the session is in AWAITING_TOOL, meaning a step paused to obtain a tool result, but resume() was called with payload=None. There is no way to continue the step without the tool outcome (result or error), so the resume is rejected rather than fabricating one.","triggerScenarios":"Thrown at phases/19-capstone-projects/20-agent-harness-loop-contract/code/main.py:239 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Pass the tool result payload, e.g. resume({\"result\": ...}) or resume({\"error\": ...})","Have the executor always attach the captured tool outcome before resuming","Distinguish resumable pauses in the UI/CLI so callers know a payload is required","Test both the result and error payload paths"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"39ea8a1c6d0b61f071226eff7ede4d4105fed820","analyzedAt":"2026-08-26T03:13:46.626Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}