zylon-ai/private-gpt · error · ValueError

Messages cannot be empty

Error message

Messages cannot be empty

What it means

ChatBody's pydantic model_validator rejects a request whose messages list is empty or missing. Every chat completion needs at least one message; the validator normalizes out-of-range sampling params first, then hard-fails on structural problems, returning HTTP 422 (pydantic ValidationError) to the API caller.

Source

Thrown at private_gpt/server/chat/chat_models.py:313

            self.temperature = None

        if self.repetition_penalty and self.repetition_penalty < 0:
            self.repetition_penalty = None

        if self.presence_penalty and self.presence_penalty < 0:
            self.presence_penalty = None

        if self.frequency_penalty and self.frequency_penalty < 0:
            self.frequency_penalty = None

        if self.seed and self.seed < 0:
            self.seed = None

        if self.max_tokens is not None and self.max_tokens <= 0:
            self.max_tokens = None

        if not self.messages:
            raise ValueError("Messages cannot be empty")

        for message in self.messages:
            if not message.content:
                raise ValueError(f"Message content cannot be empty: {message}")
            if isinstance(message.content, list):
                for block in message.content:
                    if block is None:
                        raise ValueError(f"Block cannot be None: {message}")

        if self.messages[-1].role not in self._valid_last_message_roles:
            raise ValueError(
                f"Last message role must be one of {self._valid_last_message_roles}, but got {self.messages[-1].role}"
            )

        # Check tools and tool choice
        if self.tools and self.tool_choice and self.tool_choice.type == "tool":
            if not self.tools:
                raise ValueError("Tool choice is set, but no tools are provided.")

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Ensure the client always sends at least one message, e.g. {"role":"user","content":"..."}.
  2. Guard in the UI: disable the send action until the conversation has content.
  3. If you operate the server, map pydantic ValidationError to a clean 422 response so the caller sees which field failed.

Example fix

# before
curl -X POST /v1/chat/completions -d '{"model":"x","messages":[]}'

# after
curl -X POST /v1/chat/completions -d '{"model":"x","messages":[{"role":"user","content":"hello"}]}'
Defensive patterns

Strategy: validation

Validate before calling

def valid_messages(msgs: list) -> bool:
    return bool(msgs) and all(m.get('content') for m in msgs)

Type guard

def has_messages(body: dict) -> bool:
    ms = body.get('messages')
    return isinstance(ms, list) and len(ms) > 0

Try / catch

try:
    resp = client.chat.completions.create(**body)
except ValidationError as e:
    if 'Messages cannot be empty' in str(e):
        raise UserInputError('Type a message before sending') from e
    raise

Prevention

When it happens

Trigger: POSTing to /v1/chat/completions with "messages": [] or omitting the field; a client bug that filters out all messages before sending; a proxy or test harness sending an empty conversation.

Common situations: Frontend builds the request from an empty chat state and sends it on mount; message-sanitizing middleware strips every message; scripted clients replaying truncated fixtures.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/57d8ab16c8daa624. Report an issue: GitHub.