VectifyAI/PageIndex · error · PageIndexAPIError
doc_id must be a string or a list of strings.
Error message
doc_id must be a string or a list of strings.
What it means
In the local chat surfaces, doc_id used for document targeting must be a plain string or a list of strings. Other types (int, dict, tuple, nested lists) are rejected before name resolution because the targeting block builder can only handle scalar IDs.
Source
Thrown at pageindex/local_chat.py:35
"You are PageIndex by Vectify AI, a document-focused assistant. "
"Be concise, never use emojis, and do not expose tool names."
)
# ── shared: prompt, doc targeting, validation, sync bridges ──
def _managed_instructions(client, extra_system: list[str]) -> str:
# Local: the built-in subset guidance. Own-model chat over cloud
# documents: the live instructions the MCP server serves.
base: str = _base_instructions(client)
return "\n\n".join([CHAT_HEADER, base, *extra_system])
def _doc_block(client, doc_id, scoped: bool) -> Optional[str]:
if doc_id is None:
return None
if not isinstance(doc_id, (str, list)):
raise PageIndexAPIError("doc_id must be a string or a list of "
"strings.")
# scoped: local surfaces also pass doc_id into the tool layer, so name
# resolution happens inside the allowlist — only a duplicate name
# within the targeted set shadows. Cloud tools take no allowlist
# (targeting is prompt-level), so the whole library shadows.
return doc_targeting_block(client, doc_id, scoped=scoped)
def _system_text(content: Any) -> str:
"""Text of a system/developer message: a string, or text parts joined."""
if isinstance(content, str):
return content
if isinstance(content, list):
texts = [part.get("text") for part in content
if isinstance(part, dict) and isinstance(part.get("text"), str)]
if texts:
return "\n".join(texts)
raise PageIndexAPIError(View on GitHub (pinned to afb5e11976)
Solutions
- Coerce to string: doc_id=str(doc_id) for scalars
- Flatten lists: doc_id=[str(d) for d in doc_ids]
- Validate doc_id shape at your API boundary
Example fix
# before client.chat_completions(model=..., messages=..., doc_id=doc["pk"]) # after client.chat_completions(model=..., messages=..., doc_id=str(doc["pk"]))
Defensive patterns
Strategy: type-guard
Validate before calling
if isinstance(doc_id, (list, tuple)):
doc_id = [str(d) for d in doc_id]
elif doc_id is not None:
doc_id = str(doc_id) Type guard
def is_valid_doc_id(v) -> bool:
return v is None or isinstance(v, str) or (isinstance(v, list) and all(isinstance(x, str) for x in v)) Try / catch
null
Prevention
- Coerce numeric DB keys to str before chat calls
- Flatten tuples/nested lists to a flat str list
- Validate at API boundary
When it happens
Trigger: Passing doc_id=123 (numeric DB key), doc_id=("a","b") tuple, doc_id=["a", ["b"]] nested list, or a single dict to chat_completions/responses/messages.
Common situations: IDs coming from a database as integers, JSON payloads where the ID is occasionally an object, copying cloud-API request bodies with structured selectors.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- system message content must be a string or a list of text pa
- messages must be a non-empty list.
- Each message must be a dict with 'role' and 'content'.
- chat_completions content must be a string; for structured it
- Unsupported role for chat_completions: {role!r}. Tool histor
AI-assisted analysis of VectifyAI/PageIndex@afb5e11976 (2026-08-27).
Data as JSON: /api/errors/b417a453a928f827.
Report an issue: GitHub.