{"record":{"id":"3036610f87ea5d5b","repo":"langchain-ai/deepagents","slug":"mode-must-be-one-of-thread-turn-or-call","errorCode":null,"errorMessage":"`mode` must be one of 'thread', 'turn', or 'call'.","messagePattern":"`mode` must be one of 'thread', 'turn', or 'call'\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/partners/quickjs/langchain_quickjs/middleware.py","lineNumber":102,"sourceCode":"        ),\n    )\n\n\ndef _resolve_mode(\n    *,\n    mode: str | None,\n) -> PersistenceMode:\n    \"\"\"Normalize persistence mode and enforce invariant constraints.\"\"\"\n    match mode:\n        case None | \"thread\":\n            return \"thread\"\n        case \"turn\":\n            return \"turn\"\n        case \"call\":\n            return \"call\"\n        case _:\n            msg = \"`mode` must be one of 'thread', 'turn', or 'call'.\"\n            raise ValueError(msg)\n\n\ndef _resolve_thread_id(fallback: str) -> str:\n    \"\"\"Extract `thread_id` from langgraph config or use `fallback`.\n\n    The fallback is a middleware-instance-scoped id: when the caller\n    didn't configure a `thread_id` (common for ad-hoc\n    `agent.invoke(...)` in tests or single-shot scripts), we still need\n    all resolver calls within one CodeInterpreterMiddleware lifetime to return the\n    same id — otherwise `wrap_model_call` installs tools on one REPL\n    and the eval tool looks up a different one, and the model sees\n    `ReferenceError: tools is not defined`.\n    \"\"\"\n    try:\n        config = get_config()\n    except RuntimeError:\n        # Not running inside a Runnable — test / bare-call path.\n        return fallback","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/partners/quickjs/langchain_quickjs/middleware.py#L84-L120","documentation":"The snapshot/middleware `mode` option controls snapshot granularity and must be exactly one of `'thread'`, `'turn'`, or `'call'`. `_resolve_mode` normalizes/validates the value at middleware construction and raises `ValueError` for any other string.","triggerScenarios":"Constructing the middleware (whose `__init__` calls `_resolve_mode`) with `mode=\"session\"`, `mode=\"Thread\"` (wrong case), a misspelled value like `\"turns\"`, or a non-string value.","commonSituations":"Typos in configuration files or YAML-driven setup; assuming different casing or synonyms ('session', 'request', 'run'); copying an option from another middleware that uses different mode names.","solutions":["Set `mode` to exactly `'thread'`, `'turn'`, or `'call'` (lowercase).","Validate configuration values before constructing the middleware.","Use a Literal-typed enum/constants in your config layer to catch typos early."],"exampleFix":"// before\nQuickJsMiddleware(mode=\"session\")\n\n// after\nQuickJsMiddleware(mode=\"thread\")","handlingStrategy":"validation","validationCode":"VALID_MODES = {\"thread\", \"turn\", \"call\"}\nif mode not in VALID_MODES:\n    raise ValueError(f\"mode must be one of {sorted(VALID_MODES)}, got {mode!r}\")","typeGuard":"def is_valid_mode(mode) -> bool:\n    return isinstance(mode, str) and mode in {\"thread\", \"turn\", \"call\"}","tryCatchPattern":"try:\n    mw = QuickJsMiddleware(mode=cfg[\"mode\"])\nexcept ValueError as e:\n    if \"`mode`\" in str(e):\n        mw = QuickJsMiddleware(mode=\"thread\")  # safe default","preventionTips":["Use the exact lowercase literals 'thread', 'turn', 'call'.","Type config fields as Literal[\"thread\", \"turn\", \"call\"].","Validate config files before constructing middleware."],"tags":["validation","configuration","middleware","snapshots"],"backgroundTag":"invalid-enum-value","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}