{"record":{"id":"d4fe902294aa0326","repo":"VectifyAI/PageIndex","slug":"chat-must-be-a-string-or-a-dict","errorCode":null,"errorMessage":"chat must be a string or a dict.","messagePattern":"chat must be a string or a dict\\.","errorType":"validation","errorClass":"PageIndexAPIError","httpStatus":null,"severity":"error","filePath":"pageindex/client.py","lineNumber":221,"sourceCode":"        unknown = set(conf) - {\"model\", \"backend\"}\n        if (not conf and declared is None) or unknown:\n            raise PageIndexAPIError(\n                (\"chat is an empty dict\" if not conf else\n                 f\"Unknown chat keys ({', '.join(sorted(unknown))})\")\n                + ' — chat takes \"model\" and \"backend\" (your own model), '\n                'or {\"mode\": \"cloud\"} / \"cloud\" for the managed chat.')\n        if declared == \"cloud\":\n            if conf:\n                raise PageIndexAPIError(\n                    'chat declares mode \"cloud\" but carries '\n                    f\"({', '.join(sorted(conf))}) — the managed chat \"\n                    \"selects its own model. Drop the mode, or the keys.\")\n            return \"managed\", {}\n        mapped = {\"chat_model\": conf.get(\"model\"),\n                  \"chat_backend\": conf.get(\"backend\")}\n        return \"own\", {name: value for name, value in mapped.items()\n                       if value is not None}\n    raise PageIndexAPIError(\"chat must be a string or a dict.\")\n\n\nclass PageIndexClient:\n    \"\"\"\n    Python SDK client for PageIndex.\n\n    Two independent sides, each locally run or cloud-managed:\n\n    - **index** — where documents live. With an ``api_key`` they live in\n      your PageIndex cloud account, indexed by the managed pipeline,\n      exactly like the 0.2.x SDK. Without one they are indexed on your\n      machine by the open-source pipeline (your own LLM provider key,\n      e.g. ``OPENAI_API_KEY``) and stored under ``storage_path``.\n    - **chat** — who answers. With a chat model configured\n      (``chat_model=`` / ``chat=``), the document-QA agent runs in your\n      process against your own model and credentials — in both index\n      modes. On a cloud client with no chat model, the managed cloud\n      chat answers.","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/VectifyAI/PageIndex/blob/afb5e119766630af6014b04fe8b53357527bc05e/pageindex/client.py#L203-L239","documentation":"The chat argument was neither a string, a dict/Mapping, nor None — e.g. a list, int, or object. The SDK validates chat's type up front because each type spells a different configuration shape.","triggerScenarios":"PageIndexClient(chat=[\"gpt-4o-mini\"]), chat=42, chat=True, or passing a model object instead of its name.","commonSituations":"Passing a list of model names expecting fallback behavior; passing an SDK client object (e.g. an OpenAI client) where only a config dict or name string is accepted; booleans from feature flags.","solutions":["Pass the model name as a string: chat=\"gpt-4o-mini\"","Or pass a config dict: chat={\"model\": ..., \"backend\": ...}","Provider client instances go inside the backend config, not as chat itself"],"exampleFix":"# before\nPageIndexClient(chat=[\"gpt-4o-mini\"])\n# after\nPageIndexClient(chat=\"gpt-4o-mini\")","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def valid_chat(chat) -> bool:\n    return chat is None or isinstance(chat, (str, dict))","tryCatchPattern":null,"preventionTips":["Pass model names as plain strings, provider clients/options inside backend","Reject list/bool/int values in config validation before constructing the client"],"tags":["config","chat","type-error"],"backgroundTag":"invalid-argument-type","analyzedSha":"afb5e119766630af6014b04fe8b53357527bc05e","analyzedAt":"2026-08-27T11:20:48.519Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}