VectifyAI/PageIndex · error · PageIndexAPIError
Unsupported role for chat_completions: {role!r}. Tool histor
Error message
Unsupported role for chat_completions: {role!r}. Tool history round-trips belong to responses() or messages(). What it means
chat_completions only accepts the roles system, developer, user, and assistant. Any other role — notably 'tool' — is rejected with the offending role echoed, because tool-history round-trips are handled by responses() or messages().
Source
Thrown at pageindex/local_chat.py:82
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"):
system_texts.append(_system_text(message.get("content")))
elif role in ("user", "assistant"):
content = message.get("content")
if not isinstance(content, str):
raise PageIndexAPIError(
"chat_completions content must be a string; for "
"structured items use responses() or messages()."
)
history.append({"role": role, "content": content})
else:
raise PageIndexAPIError(
f"Unsupported role for chat_completions: {role!r}. Tool "
"history round-trips belong to responses() or messages()."
)
if not history:
raise PageIndexAPIError("messages must contain a user or assistant "
"message.")
return system_texts, history
def _run_sync(coro):
from .utils import run_off_loop
return run_off_loop(asyncio.run, coro)
_SENTINEL = object()
def _stream_sync(agen_factory) -> Iterator[Any]:View on GitHub (pinned to afb5e11976)
Solutions
- Filter out non-supported roles before calling: keep only system/developer/user/assistant
- Use responses() or messages() for transcripts with tool history
- Check role strings against a whitelist when constructing messages
Example fix
# before
client.chat_completions(model=m, messages=full_transcript)
# after
msgs=[m for m in full_transcript if m["role"] in {"system","developer","user","assistant"}]
client.chat_completions(model=m, messages=msgs) Defensive patterns
Strategy: validation
Validate before calling
ALLOWED = {'system','developer','user','assistant'}
messages = [m for m in messages if m.get('role') in ALLOWED] Type guard
def is_supported_role(role) -> bool:
return role in {'system','developer','user','assistant'} Try / catch
null
Prevention
- Whitelist roles when constructing messages
- Send tool transcripts through responses()/messages()
- Lint for role typos in fixtures
When it happens
Trigger: messages containing {"role":"tool","content":...} or a typo'd role like "assitant"/"systemn".
Common situations: Feeding full agent transcripts (which include tool results) back into chat_completions, role typos, converting between Anthropic and OpenAI role vocabularies (e.g. 'tool_result').
Related errors
- Each message must be a dict with 'role' and 'content'.
- system message content must be a string or a list of text pa
- messages must be a non-empty list.
- chat_completions content must be a string; for structured it
- messages must contain a user or assistant message.
AI-assisted analysis of VectifyAI/PageIndex@afb5e11976 (2026-08-27).
Data as JSON: /api/errors/7384607ed52276e5.
Report an issue: GitHub.