{"record":{"id":"738ac7fb3d8cb7f3","repo":"meta-llama/llama","slug":"error-special-tags-are-not-allowed-as-part-of-the","errorCode":null,"errorMessage":"Error: special tags are not allowed as part of the prompt.","messagePattern":"Error: special tags are not allowed as part of the prompt\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"llama/generation.py","lineNumber":48,"sourceCode":"class CompletionPrediction(TypedDict, total=False):\n    generation: str\n    tokens: List[str]  # not required\n    logprobs: List[float]  # not required\n\n\nclass ChatPrediction(TypedDict, total=False):\n    generation: Message\n    tokens: List[str]  # not required\n    logprobs: List[float]  # not required\n\n\nDialog = List[Message]\n\nB_INST, E_INST = \"[INST]\", \"[/INST]\"\nB_SYS, E_SYS = \"<<SYS>>\\n\", \"\\n<</SYS>>\\n\\n\"\n\nSPECIAL_TAGS = [B_INST, E_INST, \"<<SYS>>\", \"<</SYS>>\"]\nUNSAFE_ERROR = \"Error: special tags are not allowed as part of the prompt.\"\n\n\nclass Llama:\n    @staticmethod\n    def build(\n        ckpt_dir: str,\n        tokenizer_path: str,\n        max_seq_len: int,\n        max_batch_size: int,\n        model_parallel_size: Optional[int] = None,\n        seed: int = 1,\n    ) -> \"Llama\":\n        \"\"\"\n        Build a Llama instance by initializing and loading a pre-trained model.\n\n        Args:\n            ckpt_dir (str): Path to the directory containing checkpoint files.\n            tokenizer_path (str): Path to the tokenizer file.","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/meta-llama/llama/blob/689c7f261b9c5514636ecc3c5fefefcbb3e6eed7/llama/generation.py#L30-L66","documentation":"This is the UNSAFE_ERROR assertion in Llama.chat_completion (llama/generation.py). It fires when any message content in the dialog already contains one of the model's reserved control tags: '[INST]', '[/INST]', '<<SYS>>', or '<</SYS>>'. The library itself wraps user prompts and system messages with these tags when building the token sequence, so pre-existing tags would let the prompt inject fake instructions or system blocks, and the guard refuses to build such a prompt.","triggerScenarios":"Calling llama.chat_completion(dialogs, ...) where any dialog message's 'content' string includes '[INST]', '[/INST]', '<<SYS>>', or '<</SYS>>' (the check is `any(tag in msg['content'] for tag in SPECIAL_TAGS for msg in dialog)`). Typical case: a chat UI that echoes a prior raw Llama-formatted prompt, or a dataset of pre-templated '[INST] ... [/INST]' examples fed directly as message content.","commonSituations":"- Feeding already-rendered Llama 2 chat prompts (from logs or sharegpt-style datasets) as message content instead of plain text.\n- Round-tripping model output back as input: an assistant reply that quotes the tags is fine, but a user message pasting them (e.g. documenting the format) trips it.\n- Prompt-injection-hardened frontends testing the boundary, or multi-turn pipelines where the system prompt was stored with its '<<SYS>>' wrappers.","solutions":["Strip or escape the special tags from every message's content before calling chat_completion (e.g. replace '[INST]'/'[/INST]'/'<<SYS>>'/'<</SYS>>' with inert variants like '\\[INST\\]')","If your data is pre-templated '[INST] ... [/INST]' text, remove the tags and pass only the inner text as user/assistant messages — the library adds tags itself","If you truly need raw control over the token stream, bypass chat_completion and call llama.generate with tokenizer.encode output you build yourself","Sanitize at ingestion: validate stored conversation data once at load time rather than at every request"],"exampleFix":"# before\ndialog = [{\"role\": \"user\", \"content\": \"[INST] tell me a joke [/INST]\"}]\nllama.chat_completion([dialog], max_gen_len=64)\n\n# after\nSPECIAL = (\"[INST]\", \"[/INST]\", \"<<SYS>>\", \"<</SYS>>\")\ndef sanitize(text):\n    for tag in SPECIAL:\n        text = text.replace(tag, tag.replace(\"[\", \"[\").replace(\"]\", \"]\"))\n    return text\ndialog = [{\"role\": \"user\", \"content\": sanitize(\"[INST] tell me a joke [/INST]\")}]\nllama.chat_completion([dialog], max_gen_len=64)","handlingStrategy":"validation","validationCode":"SPECIAL_TAGS = (\"[INST]\", \"[/INST]\", \"<<SYS>>\", \"<</SYS>>\")\n\ndef prompt_is_safe(dialog):\n    return not any(tag in m[\"content\"] for tag in SPECIAL_TAGS for m in dialog)\n\n# before calling:\nassert prompt_is_safe(dialog), \"dialog contains reserved Llama tags\"","typeGuard":"from typing import List, Dict\n\ndef is_safe_dialog(dialog: List[Dict[str, str]]) -> bool:\n    return (\n        isinstance(dialog, list)\n        and all(isinstance(m, dict) and isinstance(m.get(\"content\"), str) for m in dialog)\n        and not any(t in m[\"content\"] for t in SPECIAL_TAGS for m in dialog)\n    )","tryCatchPattern":"try:\n    result = llama.chat_completion([dialog], max_gen_len=128)\nexcept AssertionError as e:\n    if \"special tags\" in str(e):\n        dialog = [{\"role\": m[\"role\"], \"content\": sanitize(m[\"content\"])} for m in dialog]\n        result = llama.chat_completion([dialog], max_gen_len=128)\n    else:\n        raise","preventionTips":["Sanitize all user-supplied text at ingestion: replace '[INST]', '[/INST]', '<<SYS>>', '<</SYS>>' with escaped variants","Store conversations as plain role/content, never pre-rendered Llama templates","Add a unit test asserting your chat pipeline rejects or escapes reserved tags before reaching the model"],"tags":["llama","prompt-injection","chat-completion","input-validation"],"backgroundTag":null,"analyzedSha":"689c7f261b9c5514636ecc3c5fefefcbb3e6eed7","analyzedAt":"2026-08-15T02:36:29.698Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}