{"record":{"id":"a5ab7ae5d1c977c4","repo":"langchain-ai/deepagents","slug":"manual-mode-could-not-be-persisted","errorCode":null,"errorMessage":"Manual mode could not be persisted","messagePattern":"Manual mode could not be persisted","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/tui/textual_adapter.py","lineNumber":3669,"sourceCode":"                                        args = action_request.get(\"args\", {})\n                                        if isinstance(args, dict):\n                                            file_op_tracker.mark_hitl_approved(\n                                                tool_name, args\n                                            )\n\n                            elif decision_type == \"switch_manual\":\n                                if adapter._on_switch_to_manual is None:\n                                    msg = \"Manual mode callback is unavailable\"\n                                    raise RuntimeError(msg)  # noqa: TRY301  # shared turn error rendering owns this failure\n                                callback_result = adapter._on_switch_to_manual()\n                                switched = (\n                                    await callback_result\n                                    if inspect.isawaitable(callback_result)\n                                    else callback_result\n                                )\n                                if not switched:\n                                    msg = \"Manual mode could not be persisted\"\n                                    raise RuntimeError(msg)  # noqa: TRY301  # shared turn error rendering owns this failure\n                                decisions = [\n                                    cast(\"HITLDecision\", {\"type\": \"switch_manual\"})\n                                    for _ in action_requests\n                                ]\n\n                            elif decision_type == \"approve\":\n                                decisions = [\n                                    ApproveDecision(type=\"approve\")\n                                    for _ in action_requests\n                                ]\n                                tool_msgs = _interrupt_tool_rows(\n                                    review_namespace,\n                                    action_requests,\n                                    adapter._current_tool_messages,\n                                )\n                                for tool_msg in tool_msgs:\n                                    _set_running_unless_deferred(tool_msg)\n                                    adapter._sync_tool_widget(tool_msg)","sourceCodeStart":3651,"sourceCodeEnd":3687,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/tui/textual_adapter.py#L3651-L3687","documentation":"After invoking _on_switch_to_manual for a 'switch_manual' decision, a falsy return means the manual mode was not persisted (e.g. the Store write failed). The turn raises RuntimeError because continuing would leave approval state inconsistent with the user's explicit choice.","triggerScenarios":"The 'switch_manual' decision path runs, the callback returns False/None (persistence rejected or Store write failed), and the turn aborts so stale approval semantics are not silently kept.","commonSituations":"Store outage or write rejection when switching from auto-approve to manual mid-turn; callback implementations returning False on validation failure; async callback returning an awaitable resolving to False.","solutions":["Check what _on_switch_to_manual returns and why persistence failed (Store connectivity, permissions) and fix that backend issue.","Make the callback raise a descriptive error instead of returning False so the root cause is visible.","Retry the switch once connectivity is restored, then re-submit the pending tool actions.","Fall back to keeping the current approval mode with a clear UI notice if persistence cannot be guaranteed."],"exampleFix":"// before\ndef _switch_to_manual():\n    store.write(mode=\"manual\")  # returns False on failure\n    return False\n// after\ndef _switch_to_manual():\n    try:\n        store.write(mode=\"manual\")\n        return True\n    except StoreUnavailable as exc:\n        raise RuntimeError(f\"could not persist manual mode: {exc}\") from exc","handlingStrategy":"try-catch","validationCode":"result = adapter._on_switch_to_manual()\nresult = await result if inspect.isawaitable(result) else result\nif not result:\n    raise StoreWriteError(\"manual mode persistence returned failure\")","typeGuard":null,"tryCatchPattern":"try:\n    apply_hitl_decision(adapter, \"switch_manual\")\nexcept RuntimeError as exc:\n    render_turn_error(f\"switch to manual failed: {exc}\")\n    keep_current_approval_mode()","preventionTips":["Make switch callbacks raise descriptive errors instead of returning False.","Log the underlying Store failure inside the callback.","Add retry-with-backoff to approval-mode persistence writes."],"tags":["hitl","approval-mode","persistence"],"backgroundTag":"approval-mode-persist-failed","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}