{"record":{"id":"a24abe9771a5ea3e","repo":"langchain-ai/deepagents","slug":"context-hooks-server-events-must-be-a-list-of-stri","errorCode":null,"errorMessage":"context.hooks_server_events must be a list of strings or null.","messagePattern":"context\\.hooks_server_events must be a list of strings or null\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/offload_api.py","lineNumber":488,"sourceCode":"        msg = (\n            \"context.model_context_limit must be an integer or null, \"\n            f\"got {type(limit).__name__}.\"\n        )\n        raise TypeError(msg)\n    auto_approve = context.get(\"auto_approve\")\n    if auto_approve is not None and not isinstance(auto_approve, bool):\n        msg = (\n            f\"context.auto_approve must be a boolean or null, \"\n            f\"got {type(auto_approve).__name__}.\"\n        )\n        raise TypeError(msg)\n    events = context.get(\"hooks_server_events\")\n    if events is not None and (\n        not isinstance(events, list)\n        or any(not isinstance(event, str) for event in events)\n    ):\n        msg = \"context.hooks_server_events must be a list of strings or null.\"\n        raise TypeError(msg)\n\n\ndef _checkpoint_id(state: Mapping[str, object]) -> str:\n    checkpoint = state.get(\"checkpoint\")\n    value = checkpoint.get(\"checkpoint_id\") if isinstance(checkpoint, Mapping) else None\n    if not isinstance(value, str) or not value:\n        msg = \"The thread has no checkpoint to offload.\"\n        raise _OffloadConflictError(msg)\n    return value\n\n\ndef _operation_payload(\n    payload: object,\n) -> tuple[str, dict[str, Any], dict[str, object]]:\n    \"\"\"Validate the narrow client-to-operation request shape.\n\n    Args:\n        payload: Decoded request JSON.","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/offload_api.py#L470-L506","documentation":"`context.hooks_server_events` lists which hook server events the offload operation subscribes to, and must be a list of strings or null. The validator rejects non-list values and lists containing non-string elements (e.g. ints or dicts) to guarantee a clean JSON contract with the hook server.","triggerScenarios":"Calling offload() with context={'hooks_server_events': 'checkpoint'} (bare string), {'hooks_server_events': [1, 2]}, {'hooks_server_events': ('a','b')} (tuple), or {'hooks_server_events': ['ok', 42]}.","commonSituations":"Passing a comma-separated string from config instead of splitting it, building the list from enum values or ints, using a tuple/set from internal code, or JSON round-tripping that mixed types into the array.","solutions":["Split comma-separated config strings: [e.strip() for e in raw.split(',') if e.strip()].","Wrap single values in a list: events = [raw] if isinstance(raw, str) else list(raw).","Cast elements to str: [str(e) for e in events], and drop or fix non-string entries.","Pass None (or omit the key) when no hook events should be requested."],"exampleFix":"// before\ncontext = {\"hooks_server_events\": \"checkpoint.completed,thread.archived\"}\n// after\nraw = \"checkpoint.completed,thread.archived\"\ncontext = {\"hooks_server_events\": [e.strip() for e in raw.split(\",\") if e.strip()]}","handlingStrategy":"validation","validationCode":"def validate_hooks_server_events(value):\n    if value is None:\n        return True\n    return isinstance(value, list) and all(isinstance(e, str) for e in value)\n# call before offload: assert validate_hooks_server_events(ctx.get(\"hooks_server_events\"))","typeGuard":"def is_str_list_or_none(value) -> bool:\n    return value is None or (isinstance(value, list) and all(isinstance(e, str) for e in value))","tryCatchPattern":"try:\n    state = await offload(thread_id, payload)\nexcept TypeError as exc:\n    if \"hooks_server_events\" in str(exc):\n        raw = payload[\"context\"].get(\"hooks_server_events\")\n        if isinstance(raw, str):\n            raw = [e.strip() for e in raw.split(\",\") if e.strip()]\n        payload[\"context\"][\"hooks_server_events\"] = [str(e) for e in (raw or [])]\n        state = await offload(thread_id, payload)\n    else:\n        raise","preventionTips":["Split comma-separated config strings into lists at config-load time","Convert tuples/sets/generators to list(...) before building context","Cast enum or int event identifiers to str at the boundary","Pass None, not [], vs non-list shapes deliberately and consistently"],"tags":["type-error","validation","python","hooks"],"backgroundTag":"type-validation-failed","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}