{"record":{"id":"cbe1ef2030261701","repo":"meta-llama/llama","slug":"model-only-supports-system-user-and-assistan","errorCode":null,"errorMessage":"model only supports 'system', 'user' and 'assistant' roles, starting with 'system', then 'user' and alternating (u/a/u/a/u...)","messagePattern":"model only supports 'system', 'user' and 'assistant' roles, starting with 'system', then 'user' and alternating \\(u/a/u/a/u\\.\\.\\.\\)","errorType":"validation","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"llama/generation.py","lineNumber":334,"sourceCode":"        if max_gen_len is None:\n            max_gen_len = self.model.params.max_seq_len - 1\n        prompt_tokens = []\n        unsafe_requests = []\n        for dialog in dialogs:\n            unsafe_requests.append(\n                any([tag in msg[\"content\"] for tag in SPECIAL_TAGS for msg in dialog])\n            )\n            if dialog[0][\"role\"] == \"system\":\n                dialog = [\n                    {\n                        \"role\": dialog[1][\"role\"],\n                        \"content\": B_SYS\n                        + dialog[0][\"content\"]\n                        + E_SYS\n                        + dialog[1][\"content\"],\n                    }\n                ] + dialog[2:]\n            assert all([msg[\"role\"] == \"user\" for msg in dialog[::2]]) and all(\n                [msg[\"role\"] == \"assistant\" for msg in dialog[1::2]]\n            ), (\n                \"model only supports 'system', 'user' and 'assistant' roles, \"\n                \"starting with 'system', then 'user' and alternating (u/a/u/a/u...)\"\n            )\n            dialog_tokens: List[int] = sum(\n                [\n                    self.tokenizer.encode(\n                        f\"{B_INST} {(prompt['content']).strip()} {E_INST} {(answer['content']).strip()} \",\n                        bos=True,\n                        eos=True,\n                    )\n                    for prompt, answer in zip(\n                        dialog[::2],\n                        dialog[1::2],\n                    )\n                ],\n                [],","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/meta-llama/llama/blob/689c7f261b9c5514636ecc3c5fefefcbb3e6eed7/llama/generation.py#L316-L352","documentation":"This assertion inside chat_completion (llama/generation.py:334) enforces the Llama 2 chat format after the optional system message has been merged into the first user turn: the remaining dialog must strictly alternate user, assistant, user, assistant... (checks dialog[::2] are all 'user' and dialog[1::2] are all 'assistant'). Any deviation — two consecutive user messages, an assistant message first, an unknown role, or a system message placed in the middle — aborts the batch.","triggerScenarios":"Calling llama.chat_completion(dialogs, ...) with a dialog that, after a leading system message is folded into the next user turn, is not an exact u/a/u/a... sequence: e.g. [{'role':'user'},{'role':'user'}], [{'role':'assistant'},...], system appearing at index 2+, or a role string like 'tool' or 'system ' (typo/case).","commonSituations":"- Porting OpenAI-style chat logs where multiple consecutive 'user' messages are common into this stricter format.\n- Merging consecutive same-role turns incorrectly, or dropping an assistant reply during preprocessing so two user turns become adjacent.\n- Dataset bugs: role fields like 'User', 'SYSTEM', or None; system prompts injected mid-conversation by a RAG/orchestrator layer.\n- An empty dialog (len<2) with a system message: dialog[1] indexing or the parity checks fail this assert.","solutions":["Restructure the dialog before calling: one optional 'system' first, then strictly user/assistant alternating, ending anywhere (last-message role is checked separately)","Collapse consecutive user turns into one merged user message (join with newlines) and consecutive assistant turns similarly","Check for role typos/case: roles must be exactly 'system', 'user', 'assistant'","If you need a system message to apply to every turn, merge it into the first user message yourself (the code only supports it as message 0)"],"exampleFix":"# before\ndialog = [\n  {\"role\": \"system\", \"content\": \"You are helpful.\"},\n  {\"role\": \"user\", \"content\": \"hi\"},\n  {\"role\": \"user\", \"content\": \"what's the weather?\"},\n]\nllama.chat_completion([dialog], max_gen_len=64)  # AssertionError\n\n# after\ndialog = [\n  {\"role\": \"system\", \"content\": \"You are helpful.\"},\n  {\"role\": \"user\", \"content\": \"hi\\nwhat's the weather?\"},\n]\nllama.chat_completion([dialog], max_gen_len=64)","handlingStrategy":"validation","validationCode":"def dialog_roles_valid(dialog):\n    if dialog and dialog[0][\"role\"] == \"system\":\n        dialog = dialog[1:]\n    return (\n        len(dialog) >= 1\n        and all(m[\"role\"] == \"user\" for m in dialog[::2])\n        and all(m[\"role\"] == \"assistant\" for m in dialog[1::2])\n    )\n\nassert all(dialog_roles_valid(d) for d in dialogs), \"bad role alternation\"","typeGuard":"def is_valid_dialog(dialog) -> bool:\n    if not isinstance(dialog, list) or not dialog:\n        return False\n    roles = [m.get(\"role\") for m in dialog if isinstance(m, dict)]\n    if len(roles) != len(dialog):\n        return False\n    if roles and roles[0] == \"system\":\n        roles = roles[1:]\n    return all(r == \"user\" for r in roles[::2]) and all(r == \"assistant\" for r in roles[1::2])","tryCatchPattern":"try:\n    result = llama.chat_completion(dialogs, max_gen_len=128)\nexcept AssertionError as e:\n    if \"roles\" in str(e):\n        dialogs = [normalize_dialog(d) for d in dialogs]  # merge consecutive same-role turns\n        result = llama.chat_completion(dialogs, max_gen_len=128)\n    else:\n        raise","preventionTips":["Normalize conversations at ingestion: merge consecutive same-role messages, keep system only at position 0","Whitelist roles to {'system','user','assistant'} and reject/case-fold anything else","Add a preflight validator that runs both role checks (alternation + last-is-user) before every batch call"],"tags":["llama","chat-completion","dialog-format","input-validation"],"backgroundTag":null,"analyzedSha":"689c7f261b9c5514636ecc3c5fefefcbb3e6eed7","analyzedAt":"2026-08-15T02:36:29.698Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}