VectifyAI/PageIndex · error · PageIndexAPIError

messages must be a non-empty string or a list of message dic

Error message

messages must be a non-empty string or a list of message dicts.

What it means

run_messages() normalizes its input: a non-blank string becomes a single user message, otherwise messages must be a non-empty list of dicts. This guard fires before any network traffic when the input is neither — e.g. an empty string, empty list, a list containing non-dicts, or a bare dict/tuple.

Source

Thrown at pageindex/local_chat.py:1029

                 top_p: Optional[float] = None,
                 top_k: Optional[int] = None,
                 stop_sequences: Optional[list[str]] = None,
                 max_turns: Optional[int] = None,
                 thinking: Optional[dict] = None,
                 extra_body: Optional[dict] = None,
                 extra_headers: Optional[dict] = None,
                 backend: Optional[dict] = None,
                 ) -> Union[dict, Iterator[Any]]:
    from .integrations.anthropic_sdk import build_anthropic_tools

    _require_anthropic()
    import anthropic
    _validate_max_turns(max_turns)
    if isinstance(messages, str) and messages.strip():
        messages = [{"role": "user", "content": messages}]
    if (not isinstance(messages, list) or not messages
            or not all(isinstance(message, dict) for message in messages)):
        raise PageIndexAPIError("messages must be a non-empty string or a "
                                "list of message dicts.")
    scope = client._local_doc_scope(doc_id)
    block = _doc_block(client, doc_id, scoped=scope is not None)
    prepared = [dict(message) for message in messages]
    passthrough = {key: value for key, value in {
        "temperature": temperature, "top_p": top_p, "top_k": top_k,
        "stop_sequences": stop_sequences, "thinking": thinking,
        "extra_body": extra_body, "extra_headers": extra_headers,
    }.items() if value is not None}
    system_blocks = _anthropic_system(client, system, block)
    # Top-level cache_control: the server re-marks the newest block each
    # turn, so the loop re-reads the growing conversation from cache.
    # Counts toward the 4-breakpoint limit (live-verified 400 past it).
    cached: dict[str, Any] = (
        {"cache_control": {"type": "ephemeral"}}
        if _cache_marks(system_blocks, prepared) < 4 else {})
    # Tools before the transport: on a bridge client building them is
    # network I/O, and a failure there must not strand the client below.

View on GitHub (pinned to afb5e11976)

Solutions

  1. Ensure messages is a non-empty string or a list of dicts like [{'role': 'user', 'content': '...'}]
  2. Filter/validate upstream user input before calling messages()
  3. If the list may be empty, skip the call entirely (there is nothing to send)

Example fix

# before
client.messages(user_input)  # user_input may be ""
# after
if isinstance(user_input, str) and user_input.strip():
    client.messages(user_input)
Defensive patterns

Strategy: validation

Validate before calling

def valid_messages(msgs) -> bool:
    if isinstance(msgs, str):
        return bool(msgs.strip())
    return (isinstance(msgs, list) and bool(msgs)
            and all(isinstance(m, dict) for m in msgs))

if not valid_messages(user_msgs):
    return  # nothing to send

Type guard

def is_message_list(v) -> bool:
    return (isinstance(v, list) and len(v) > 0
            and all(isinstance(m, dict) and 'role' in m and 'content' in m for m in v))

Prevention

When it happens

Trigger: client.messages(""), client.messages([]), client.messages(["hello"]) (list of strings), or client.messages(None) — any input that is not a non-blank string or a list of message dicts.

Common situations: Forwarding user input that can be empty (a blank chat box); passing [{'role': 'user', 'content': ...}, 'extra'] by accident; template bugs producing None.

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


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