VectifyAI/PageIndex · error · PageIndexAPIError
system message content must be a string or a list of text pa
Error message
system message content must be a string or a list of text parts.
What it means
When building the managed system prompt, system/developer message content must be either a string or a list of parts each containing a 'text' key with a string value. Content that is a list with no valid text parts (e.g. only image parts, empty list, or parts whose text is not a string) raises this error.
Source
Thrown at pageindex/local_chat.py:53
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(
"system message content must be a string or a list of text parts."
)
def _split_chat_messages(messages) -> "tuple[list[str], list[dict]]":
"""Validate the chat_completions surface's messages: system/developer
content joins the managed instructions; user/assistant history passes
through. Tool-history round-trips belong to responses()/messages()."""
if not isinstance(messages, list) or not messages:
raise PageIndexAPIError("messages must be a non-empty list.")
system_texts: list[str] = []
history: list[dict] = []
for message in messages:
if not isinstance(message, dict) or "role" not in message:
raise PageIndexAPIError(
"Each message must be a dict with 'role' and 'content'.")
role = message["role"]
if role in ("system", "developer"):View on GitHub (pinned to afb5e11976)
Solutions
- Use a plain string for system/developer content
- Extract only text parts and join them before passing
- If you need multimodal system content, move it to the user turn or use responses()/messages()
Example fix
# before
messages=[{"role":"system","content":[{"type":"text","text": 42}]}]
# after
messages=[{"role":"system","content":"You are a helpful assistant."}] Defensive patterns
Strategy: type-guard
Validate before calling
for m in messages:
if m['role'] in ('system','developer'):
m['content'] = m['content'] if isinstance(m['content'], str) else "\n".join(p['text'] for p in m['content'] if isinstance(p, dict) and isinstance(p.get('text'), str)) Type guard
def has_valid_system_content(content) -> bool:
if isinstance(content, str): return True
return isinstance(content, list) and any(isinstance(p, dict) and isinstance(p.get('text'), str) for p in content) Try / catch
null
Prevention
- Use plain strings for system prompts
- Don't forward multimodal system content from other SDKs
- Extract text parts when adapting request bodies
When it happens
Trigger: Passing a system message with content=[{"type":"image_url",...}], content=[], or content=[{"text": 123}] to chat_completions.
Common situations: Forwarding raw OpenAI/Anthropic request bodies where system content is multimodal, constructing messages from templating code that emits non-string text, copying examples with content-part arrays.
Related errors
- 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
- messages must contain a user or assistant message.
AI-assisted analysis of VectifyAI/PageIndex@afb5e11976 (2026-08-27).
Data as JSON: /api/errors/a315f1fb9a70d6b3.
Report an issue: GitHub.