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

  1. Use a plain string for system/developer content
  2. Extract only text parts and join them before passing
  3. 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

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


AI-assisted analysis of VectifyAI/PageIndex@afb5e11976 (2026-08-27). Data as JSON: /api/errors/a315f1fb9a70d6b3. Report an issue: GitHub.