diff --git a/libs/partners/openai/langchain_openai/chat_models/base.py b/libs/partners/openai/langchain_openai/chat_models/base.py index 8e2473fe221..efaff493f4b 100644 --- a/libs/partners/openai/langchain_openai/chat_models/base.py +++ b/libs/partners/openai/langchain_openai/chat_models/base.py @@ -14,6 +14,7 @@ from __future__ import annotations import base64 +import inspect import json import logging import os @@ -1184,6 +1185,20 @@ class BaseChatOpenAI(BaseChatModel): sync_api_key_value, async_api_key_value = _resolve_sync_and_async_api_keys( self.openai_api_key ) + # Surface the sync/async constraint at construction time so callers + # don't first discover it on a runtime invocation. An async-callable + # api_key means the sync client cannot be built, and sync entry + # points (invoke/stream) will fail with a clearer ValueError later. + if inspect.iscoroutinefunction(self.openai_api_key): + warnings.warn( + "An async callable was provided for `openai_api_key`. " + "The sync client will not be available; only async entry " + "points (`ainvoke`, `astream`, ...) will work. To use sync " + "methods, provide a string or a sync callable for the API " + "key.", + UserWarning, + stacklevel=2, + ) client_params: dict = { "organization": self.openai_organization, diff --git a/libs/partners/openai/tests/unit_tests/chat_models/test_base.py b/libs/partners/openai/tests/unit_tests/chat_models/test_base.py index 64d6237d60c..355decaa121 100644 --- a/libs/partners/openai/tests/unit_tests/chat_models/test_base.py +++ b/libs/partners/openai/tests/unit_tests/chat_models/test_base.py @@ -3803,3 +3803,31 @@ def test_defer_loading_in_responses_api_payload() -> None: assert weather_tool["defer_loading"] is True assert weather_tool["type"] == "function" assert {"type": "tool_search"} in result["tools"] + + +def test_async_callable_api_key_warns_at_construction() -> None: + """An async callable api_key should warn at construction time.""" + + async def async_api_key() -> str: + return "sk-test" + + with pytest.warns(UserWarning, match="async callable"): + llm = ChatOpenAI(model="gpt-4o-mini", openai_api_key=async_api_key) + + assert llm.client is None + assert llm.root_client is None + assert llm.async_client is not None + + with pytest.raises(ValueError, match="Sync client is not available"): + llm.invoke("hello") + + +def test_sync_callable_api_key_does_not_warn() -> None: + """A sync callable api_key must not trigger the async-callable warning.""" + + def sync_api_key() -> str: + return "sk-test" + + with warnings.catch_warnings(): + warnings.simplefilter("error", UserWarning) + ChatOpenAI(model="gpt-4o-mini", openai_api_key=sync_api_key)