diff --git a/libs/partners/xai/langchain_xai/chat_models.py b/libs/partners/xai/langchain_xai/chat_models.py index 359667376e4..a5cbec2f2e5 100644 --- a/libs/partners/xai/langchain_xai/chat_models.py +++ b/libs/partners/xai/langchain_xai/chat_models.py @@ -535,6 +535,21 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override] def _resolve_model_profile(self) -> ModelProfile | None: return _get_default_model_profile(self.model_name) or None + def _get_request_payload( + self, + input_: LanguageModelInput, + *, + stop: list[str] | None = None, + **kwargs: Any, + ) -> dict: + payload = super()._get_request_payload(input_, stop=stop, **kwargs) + # The grok-3 family rejects the `stop` parameter with a 400 error + # rather than ignoring it. Drop it silently so calls that set `stop` + # for other models in a shared code path don't hard-fail on grok-3. + if self.model_name and self.model_name.startswith("grok-3"): + payload.pop("stop", None) + return payload + def _stream(self, *args: Any, **kwargs: Any) -> Iterator[ChatGenerationChunk]: """Route to Chat Completions or Responses API.""" if self._use_responses_api({**kwargs, **self.model_kwargs}): diff --git a/libs/partners/xai/tests/unit_tests/test_chat_models.py b/libs/partners/xai/tests/unit_tests/test_chat_models.py index 1e4b3d30672..d70e1f1c73c 100644 --- a/libs/partners/xai/tests/unit_tests/test_chat_models.py +++ b/libs/partners/xai/tests/unit_tests/test_chat_models.py @@ -159,3 +159,22 @@ def test_stream_usage_metadata() -> None: model = ChatXAI(model=MODEL_NAME, stream_usage=False) assert model.stream_usage is False + + +def test_chat_xai_grok_3_strips_stop_from_payload() -> None: + """grok-3 family rejects the `stop` param; ensure it's stripped from payload.""" + llm = ChatXAI(model="grok-3", api_key=SecretStr("test-api-key"), stop=["END"]) + payload = llm._get_request_payload([HumanMessage(content="hi")]) + assert "stop" not in payload + + # Also covers forward-compat variants like `grok-3-mini`, `grok-3-fast`, etc. + llm_variant = ChatXAI( + model="grok-3-mini", api_key=SecretStr("test-api-key"), stop=["END"] + ) + payload_variant = llm_variant._get_request_payload([HumanMessage(content="hi")]) + assert "stop" not in payload_variant + + # Sanity check: other models still forward `stop`. + llm_other = ChatXAI(model="grok-4", api_key=SecretStr("test-api-key"), stop=["END"]) + payload_other = llm_other._get_request_payload([HumanMessage(content="hi")]) + assert payload_other.get("stop") == ["END"]