AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

ChatOpenRouter: Timeout Parameter Interpreted As Milliseconds Instead Of Seconds

ChatOpenRouter passes the timeout value directly to the OpenRouter SDK as timeout_ms, but LangChain convention expects seconds. Passing timeout=120.0 results in a 120ms timeout instead of 120s, causing premature failures or long silent retries.

highConfidence 95%LangchainAffected V0.2.8

Origin Analysis

The request_timeout field is typed as int, aliased to 'timeout', documented in milliseconds, and forwarded verbatim to the SDK as timeout_ms. This violates the LangChain seconds-based timeout contract and rejects fractional seconds.
import asyncio, time from langchain_openrouter import ChatOpenRouter async def main(): client = ChatOpenRouter(model='google/gemini-3.7-flash', timeout=120.0, max_retries=0) t0 = time.time() try: r = await client.ainvoke('Hello!') print('OK', r.content) except Exception as e: print(f'{type(e).__name__} after {time.time()-t0:.1f}s: {e}') asyncio.run(main()) # Observed: hangs indefinitely or fails with ReadTimeout after 120ms instead of 120s

Fixing Code Block

Edge Case Audit

Users who previously worked around the bug by passing milliseconds directly (e.g., timeout=120000) will now experience a 1000x reduction in timeout after upgrading. This is a breaking change for such workarounds. Rollback: revert the field type and remove the multiplication. Ensure integration tests cover fractional seconds and verify retry behavior does not cause excessive delays.

Ecosystem Topology