{"record":{"id":"14c68db95056d92a","repo":"zylon-ai/private-gpt","slug":"user-block-i-does-not-start-with-a-user-message","errorCode":null,"errorMessage":"User block {i} does not start with a user message: {block[0]}","messagePattern":"User block (.+?) does not start with a user message: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"private_gpt/components/chat/processors/chat_history/memory/utils/repairs.py","lineNumber":135,"sourceCode":"\ndef _assert_user_blocks(chat_history: list[ChatMessage], strict: bool) -> None:\n    \"\"\"A user block should follow a regex pattern.\n\n    Strict mode: (user, (assistant, tool)*, assistant)\n    Non-strict mode: (user, (assistant, tool)*, assistant?)\n\n    \"\"\"\n    if not chat_history:\n        return\n\n    matrix = get_user_blocks(chat_history)\n    for i, block in enumerate(matrix):\n        if not block:\n            raise ValueError(f\"User block {i} is empty.\")\n\n        # Validate the first and last messages in the block\n        if block[0].role != \"user\":\n            raise ValueError(\n                f\"User block {i} does not start with a user message: {block[0]}\"\n            )\n\n        if len(block) == 1:\n            # No more validation needed for a single user message block\n            continue\n\n        # Validate the last message in the block\n        if strict and block[-1].role != \"assistant\":\n            raise ValueError(\n                f\"User block {i} does not end with an assistant message: {block[-1]}\"\n            )\n        elif not strict and block[-1].role not in [\"assistant\", \"tool\"]:\n            raise ValueError(\n                f\"User block {i} does not end with an assistant or tool message: {block[-1]}\"\n            )\n\n        # Validate the tool messages","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/chat/processors/chat_history/memory/utils/repairs.py#L117-L153","documentation":"User-block structure validation: each block produced by get_user_blocks must start with a role=='user' message. Because blocks are defined as starting at user messages, a block whose first message is not 'user' means the splitting invariant broke (or the history was mutated between split and validation).","triggerScenarios":"Calling repair_without_tools()/repair_with_tools() on a conversation whose first non-system message is not a user message (e.g. assistant-first conversation), so the leading chunk fails the block[0].role != 'user' check.","commonSituations":"Histories that begin with an assistant greeting; a tool message appearing before any user message; custom history loaders that reorder messages.","solutions":["Ensure conversations passed to repair_* start with a user message after system messages","Prepend a synthetic user message for assistant-first histories","Fix upstream code that injects assistant/tool messages before the first user turn"],"exampleFix":"# before\nrepaired = repair_with_tools(conversation_messages)\n\n# after\nif conversation_messages and conversation_messages[0].role != \"user\":\n    conversation_messages = [ChatMessage(role=MessageRole.USER, content=\"(start)\")] + conversation_messages\nrepaired = repair_with_tools(conversation_messages)","handlingStrategy":"validation","validationCode":"if conversation_messages and conversation_messages[0].role != \"user\":\n    conversation_messages = [ChatMessage(role=MessageRole.USER, content=\"(start)\")] + conversation_messages","typeGuard":"def starts_with_user(history: list[ChatMessage]) -> bool:\n    return bool(history) and history[0].role == \"user\"","tryCatchPattern":"try:\n    repaired = repair_with_tools(conversation_messages)\nexcept ValueError as e:\n    if \"does not start with a user message\" in str(e):\n        conversation_messages = [ChatMessage(role=MessageRole.USER, content=\"(start)\")] + conversation_messages\n        repaired = repair_with_tools(conversation_messages)\n    else:\n        raise","preventionTips":["Normalize histories to user-first before repair","Reject assistant-first transcripts at ingestion or prepend a synthetic user turn","Log the offending block index to locate the producer bug quickly"],"tags":["chat-history","validation","repair","message-order"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}