{"record":{"id":"b90fabcd18f96a59","repo":"VectifyAI/PageIndex","slug":"system-must-be-a-string-or-a-list-of-blocks","errorCode":null,"errorMessage":"system must be a string or a list of blocks.","messagePattern":"system must be a string or a list of blocks\\.","errorType":"validation","errorClass":"PageIndexAPIError","httpStatus":null,"severity":"error","filePath":"pageindex/local_chat.py","lineNumber":935,"sourceCode":"def _anthropic_system(client, extra_system, block: Optional[str]) -> list[dict]:\n    \"\"\"System blocks: cache_control marks the stable managed prefix only\n    (the API allows 4 breakpoints total — the varying doc block and caller\n    blocks must not consume the budget); the doc block and caller system\n    content follow as their own blocks.\"\"\"\n    blocks = [{\"type\": \"text\",\n               \"text\": CHAT_HEADER + \"\\n\\n\" + _base_instructions(client),\n               \"cache_control\": {\"type\": \"ephemeral\"}}]\n    if block:\n        blocks.append({\"type\": \"text\", \"text\": block})\n    if extra_system is None:\n        return blocks\n    if isinstance(extra_system, str):\n        if extra_system.strip():\n            blocks.append({\"type\": \"text\", \"text\": extra_system})\n        return blocks\n    if isinstance(extra_system, list):\n        return blocks + list(extra_system)\n    raise PageIndexAPIError(\"system must be a string or a list of blocks.\")\n\n\ndef _cache_marks(system_blocks, messages) -> int:\n    \"\"\"Breakpoints already on the request. The API allows 4 total; the\n    top-level moving breakpoint is only added when it fits.\"\"\"\n    blocks = list(system_blocks)\n    for message in messages:\n        content = message.get(\"content\")\n        if isinstance(content, list):\n            blocks += [b for b in content if isinstance(b, dict)]\n    return sum(1 for b in blocks\n               if isinstance(b, dict) and b.get(\"cache_control\"))\n\n\ndef _dump_block(block) -> Any:\n    \"\"\"A content block as a plain JSON dict, minus SDK-internal fields the\n    API rejects (ParsedBetaTextBlock.__api_exclude__, e.g. parsed_output)\n    and unset response-only defaults (exclude_unset, like the SDK's own","sourceCodeStart":917,"sourceCodeEnd":953,"githubUrl":"https://github.com/VectifyAI/PageIndex/blob/afb5e119766630af6014b04fe8b53357527bc05e/pageindex/local_chat.py#L917-L953","documentation":"The messages() API accepts extra_system as either a plain string or a list of Anthropic system blocks. _anthropic_system() validates this before building the request; anything else (dict, int, None-as-object, tuple) is rejected with this error.","triggerScenarios":"Calling client.messages(messages, extra_system={'type': 'text', ...}) (a single block dict instead of a list), or passing a non-string/non-list value such as an int or tuple.","commonSituations":"Assuming a single block dict is accepted like in raw Anthropic SDK calls; passing JSON-decoded data whose shape changed; forgetting to wrap one block in [ ].","solutions":["Pass a plain string: extra_system=\"Always answer in French\"","Or a list of blocks: extra_system=[{'type': 'text', 'text': '...'}]","If the value comes from config, validate its shape before the call"],"exampleFix":"# before\nclient.messages(\"hi\", extra_system={\"type\": \"text\", \"text\": \"Be brief\"})\n# after\nclient.messages(\"hi\", extra_system=[{\"type\": \"text\", \"text\": \"Be brief\"}])","handlingStrategy":"type-guard","validationCode":"if extra_system is not None and not (isinstance(extra_system, str) or isinstance(extra_system, list)):\n    raise TypeError('extra_system must be str or list of blocks')","typeGuard":"def is_valid_system(v) -> bool:\n    return v is None or isinstance(v, str) or (isinstance(v, list) and all(isinstance(b, dict) for b in v))","tryCatchPattern":null,"preventionTips":["Always wrap single blocks in a list","Validate config-sourced system prompts before the call"],"tags":["anthropic","validation","system-prompt","type-error"],"backgroundTag":"invalid-argument-type","analyzedSha":"afb5e119766630af6014b04fe8b53357527bc05e","analyzedAt":"2026-08-27T11:20:48.519Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}