{"record":{"id":"fade166faf2ab107","repo":"zylon-ai/private-gpt","slug":"message-content-cannot-be-empty-message","errorCode":null,"errorMessage":"Message content cannot be empty: {message}","messagePattern":"Message content cannot be empty: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"private_gpt/server/chat/chat_models.py","lineNumber":317,"sourceCode":"\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.\")\n            if self.tool_choice.name not in [tool.name for tool in self.tools]:\n                raise ValueError(\n                    f\"Tool choice '{self.tool_choice}' is not in the provided tools.\"\n                )","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/server/chat/chat_models.py#L299-L335","documentation":"The ChatBody validator iterates all messages and rejects any message whose content is empty (empty string, empty list, or None). Unlike sampling params, empty content is not auto-corrected — it is a client error, surfaced as ValidationError/422 with the offending message embedded in the error text.","triggerScenarios":"A message like {\"role\":\"user\",\"content\":\"\"} or {\"role\":\"assistant\",\"content\":[]} in messages; clients that append an empty placeholder message before streaming; trimming logic that empties content instead of dropping the message.","commonSituations":"Chat UIs that submit before the user types anything; assistant messages serialized with content removed when tool_calls-only messages are converted; upstream services forwarding pre-emptied content fields.","solutions":["Drop empty messages client-side before sending (filter m for m.content).","For tool-call-only assistant turns, set content to a non-empty placeholder or a content block list that is non-empty.","Add a client-side assert that every message has truthy content."],"exampleFix":"# before\nmessages = history + [{\"role\": \"user\", \"content\": user_text}]  # user_text may be \"\"\n\n# after\nmessages = [m for m in history if m.get(\"content\")] \nif user_text:\n    messages.append({\"role\": \"user\", \"content\": user_text})","handlingStrategy":"validation","validationCode":"clean = [m for m in messages if m.get('content')]\nassert clean, 'refusing to send: all messages empty'","typeGuard":"def all_content_nonempty(msgs: list[dict]) -> bool:\n    return all(bool(m.get('content')) for m in msgs)","tryCatchPattern":"except ValidationError as e:\n    if 'content cannot be empty' in str(e):\n        messages = [m for m in messages if m.get('content')]\n        resp = client.create(messages=messages, **rest)\n    else:\n        raise","preventionTips":["Filter falsy-content messages in the request builder","Give tool-call-only assistant turns a placeholder content string","Unit-test edge cases: empty string content, empty block list"],"tags":["validation","chat-api","empty-content","http-422"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}