{"record":{"id":"57d8ab16c8daa624","repo":"zylon-ai/private-gpt","slug":"messages-cannot-be-empty","errorCode":null,"errorMessage":"Messages cannot be empty","messagePattern":"Messages cannot be empty","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"private_gpt/server/chat/chat_models.py","lineNumber":313,"sourceCode":"            self.temperature = None\n\n        if self.repetition_penalty and self.repetition_penalty < 0:\n            self.repetition_penalty = None\n\n        if self.presence_penalty and self.presence_penalty < 0:\n            self.presence_penalty = None\n\n        if self.frequency_penalty and self.frequency_penalty < 0:\n            self.frequency_penalty = None\n\n        if self.seed and self.seed < 0:\n            self.seed = None\n\n        if self.max_tokens is not None and self.max_tokens <= 0:\n            self.max_tokens = None\n\n        if not self.messages:\n            raise ValueError(\"Messages cannot be empty\")\n\n        for message in self.messages:\n            if not message.content:\n                raise ValueError(f\"Message content cannot be empty: {message}\")\n            if isinstance(message.content, list):\n                for block in message.content:\n                    if block is None:\n                        raise ValueError(f\"Block cannot be None: {message}\")\n\n        if self.messages[-1].role not in self._valid_last_message_roles:\n            raise ValueError(\n                f\"Last message role must be one of {self._valid_last_message_roles}, but got {self.messages[-1].role}\"\n            )\n\n        # Check tools and tool choice\n        if self.tools and self.tool_choice and self.tool_choice.type == \"tool\":\n            if not self.tools:\n                raise ValueError(\"Tool choice is set, but no tools are provided.\")","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/server/chat/chat_models.py#L295-L331","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the client always sends at least one message, e.g. {\"role\":\"user\",\"content\":\"...\"}.","Guard in the UI: disable the send action until the conversation has content.","If you operate the server, map pydantic ValidationError to a clean 422 response so the caller sees which field failed."],"exampleFix":"# before\ncurl -X POST /v1/chat/completions -d '{\"model\":\"x\",\"messages\":[]}'\n\n# after\ncurl -X POST /v1/chat/completions -d '{\"model\":\"x\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'","handlingStrategy":"validation","validationCode":"def valid_messages(msgs: list) -> bool:\n    return bool(msgs) and all(m.get('content') for m in msgs)","typeGuard":"def has_messages(body: dict) -> bool:\n    ms = body.get('messages')\n    return isinstance(ms, list) and len(ms) > 0","tryCatchPattern":"try:\n    resp = client.chat.completions.create(**body)\nexcept ValidationError as e:\n    if 'Messages cannot be empty' in str(e):\n        raise UserInputError('Type a message before sending') from e\n    raise","preventionTips":["Disable the send button until user input exists","Assert message list non-empty in request-builder unit tests","Map pydantic ValidationError to friendly 422s server-side"],"tags":["validation","chat-api","http-422","request-body"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}