{"record":{"id":"0aa381d1f8f57fd0","repo":"unslothai/unsloth","slug":"name-is-only-valid-on-role-tool-messages","errorCode":null,"errorMessage":"\"name\" is only valid on role=\"tool\" messages.","messagePattern":"\"name\" is only valid on role=\"tool\" messages\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/models/inference.py","lineNumber":1260,"sourceCode":"        ),\n    )\n\n    @field_validator(\"reasoning_content\", mode = \"before\")\n    @classmethod\n    def _ignore_non_string_reasoning(cls, value):\n        # This field used to be ignored as an unknown key. Some compatible\n        # gateways send structured reasoning, so declaring the string form must\n        # not turn those previously accepted requests into validation errors.\n        return value if isinstance(value, str) else None\n\n    @model_validator(mode = \"after\")\n    def _validate_role_shape(self) -> \"ChatMessage\":\n        if self.tool_calls is not None and self.role != \"assistant\":\n            raise ValueError('\"tool_calls\" is only valid on role=\"assistant\" messages.')\n        if self.tool_call_id is not None and self.role != \"tool\":\n            raise ValueError('\"tool_call_id\" is only valid on role=\"tool\" messages.')\n        if self.name is not None and self.role != \"tool\":\n            raise ValueError('\"name\" is only valid on role=\"tool\" messages.')\n\n        if self.role == \"tool\":\n            # tool_call_id resolution happens at ChatCompletionRequest scope.\n            # OpenAI accepts empty tool results (commands with no output);\n            # normalize to \"\" instead of a 400 agentic clients treat as fatal.\n            if self.content is None or self.content == []:\n                self.content = \"\"\n        elif self.role == \"assistant\":\n            # Post-Stop sentinel: collapse content=\"\" / [] to None.\n            if (self.content == \"\" or self.content == []) and not self.tool_calls:\n                self.content = None\n        else:  # \"user\" | \"system\"\n            if self.content is None or self.content == []:\n                raise ValueError(f'role=\"{self.role}\" messages require \"content\".')\n        return self\n\n\nclass ThinkingConfig(BaseModel):","sourceCodeStart":1242,"sourceCodeEnd":1278,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/models/inference.py#L1242-L1278","documentation":"Raised by the ChatMessage model validator when the name field is set on a message whose role is not \"tool\". In the OpenAI schema, name on a message identifies which tool produced a tool result; on other roles it is not accepted by this server.","triggerScenarios":"Sending {\"role\": \"user\", \"name\": \"Alice\", \"content\": \"hi\"} to /v1/chat/completions — some clients still send the legacy name-on-user-message pattern. Also {\"role\": \"system\", \"name\": \"persona\"} from older OpenAI examples.","commonSituations":"Legacy OpenAI API examples that named user/system messages; multi-user chat front-ends forwarding a username field; SDK versions where name was tolerated on all roles and a strict update now rejects it.","solutions":["Remove name from non-tool messages; prefix the identity into content instead (e.g. 'Alice: hi').","For tool results, ensure role=\"tool\" with both tool_call_id and, if used, name.","Update to a schema where only role=\"tool\" messages carry name."],"exampleFix":"# before\n{\"role\": \"user\", \"name\": \"alice\", \"content\": \"hello\"}\n\n# after\n{\"role\": \"user\", \"content\": \"alice: hello\"}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def message_ok(msg: dict) -> bool:\n    if msg.get('name') is not None:\n        return msg.get('role') == 'tool'\n    return True","tryCatchPattern":null,"preventionTips":["Drop the legacy name-on-user/system pattern; inline identity into content","Keep a schema (pydantic/OpenAPI) on the client and validate before send","Watch for SDK changes that stop tolerating name on non-tool roles"],"tags":["pydantic","validation","openai","chat-completions","legacy-schema"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}