{"record":{"id":"a930c66b9a0f000a","repo":"sgl-project/sglang","slug":"exactly-one-of-prompt-or-messages-must-be-prov","errorCode":null,"errorMessage":"Exactly one of 'prompt' or 'messages' must be provided.","messagePattern":"Exactly one of 'prompt' or 'messages' must be provided\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/entrypoints/openai/protocol.py","lineNumber":1467,"sourceCode":"    model: str = DEFAULT_MODEL_NAME\n    prompt: Optional[Union[str, List[str]]] = None\n    messages: Optional[List[ChatCompletionMessageParam]] = None\n    tools: Optional[List[Tool]] = Field(default=None, examples=[None])\n    tool_choice: Optional[Union[ToolChoice, Literal[\"auto\", \"required\", \"none\"]]] = (\n        Field(default=None, examples=[\"auto\"])\n    )\n    reasoning_effort: ReasoningEffortType = None\n    continue_final_message: bool = False\n    chat_template_kwargs: Optional[Dict] = None\n    add_special_tokens: bool = Field(\n        default=True,\n        description=\"whether to add model-specific special tokens (e.g. BOS/EOS) during encoding.\",\n    )\n\n    @model_validator(mode=\"after\")\n    def validate_tokenize_input(self) -> TokenizeRequest:\n        if (self.prompt is None) == (self.messages is None):\n            raise ValueError(\"Exactly one of 'prompt' or 'messages' must be provided.\")\n        return self\n\n    def to_chat_completion_request(self) -> ChatCompletionRequest:\n        data = self.model_dump(\n            exclude={\"prompt\", \"add_special_tokens\"},\n            exclude_none=True,\n        )\n        extra = getattr(self, \"__pydantic_extra__\", None)\n        if extra:\n            data.update(extra)\n        return ChatCompletionRequest.model_validate(data)\n\n\nclass TokenizeResponse(BaseModel):\n    \"\"\"Response schema for the /tokenize endpoint.\"\"\"\n\n    tokens: Union[List[int], List[List[int]]]\n    count: Union[int, List[int]]","sourceCodeStart":1449,"sourceCodeEnd":1485,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/entrypoints/openai/protocol.py#L1449-L1485","documentation":"TokenizeRequest.validate_tokenize_input requires exactly one of 'prompt' or 'messages' to be set: the XOR condition fails if both are provided or neither is. The tokenizer needs an unambiguous input source.","triggerScenarios":"POST /tokenize with both prompt and messages in the body, or with neither field.","commonSituations":"Client code that always sends messages and also includes a leftover prompt field; conditional building that omits both when a variable is empty.","solutions":["Send only prompt (string) for raw text tokenization, or only messages for chat tokenization","Check your request builder for accidental default empty values of both fields"],"exampleFix":"// before\n{\"model\": \"m\", \"prompt\": \"hi\", \"messages\": [{\"role\":\"user\",\"content\":\"hi\"}]}\n// after\n{\"model\": \"m\", \"prompt\": \"hi\"}","handlingStrategy":"validation","validationCode":"has_p = \"prompt\" in body and body[\"prompt\"] is not None\nhas_m = \"messages\" in body and body[\"messages\"] is not None\nassert has_p != has_m, \"send exactly one of prompt/messages\"","typeGuard":"def tokenize_payload_ok(b): return (b.get('prompt') is None) != (b.get('messages') is None)","tryCatchPattern":null,"preventionTips":["Build request dicts explicitly per mode, never include both keys"],"tags":["tokenization","validation","openai-api","sglang"],"backgroundTag":"mutually-exclusive-parameters","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}