{"record":{"id":"d10bb570745465aa","repo":"virattt/ai-hedge-fund","slug":"no-v2-client-for-provider-model-model-suppo","errorCode":null,"errorMessage":"No v2 client for {provider} (model {model}). Supported: {', '.join(sorted(SUPPORTED_PROVIDERS))}.","messagePattern":"No v2 client for (.+?) \\(model (.+?)\\)\\. Supported: (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"hedge_fund/llm/client.py","lineNumber":105,"sourceCode":"    model: str | None = None,\n    timeout: float = 60.0,\n    max_tokens: int = 4096,\n    on_token: TokenListener = None,\n) -> ChatLLM:\n    \"\"\"Build the client for a model id, routed by the registry's provider.\n\n    The id comes from the caller, else HEDGE_FUND_LLM_MODEL, else DEFAULT_MODEL — the\n    same seam the TUI's picker writes to. Raises with the name of the missing\n    environment variable, because that is the only thing the user can act on.\n    \"\"\"\n    model = model or os.environ.get(\"HEDGE_FUND_LLM_MODEL\") or DEFAULT_MODEL\n    provider = provider_for(model)\n    if provider is None:\n        # Unlisted ids still work: a model newer than the registry should not\n        # need a code change. Anthropic is the default transport.\n        provider = \"Anthropic\"\n    if not is_supported(provider):\n        raise ValueError(\n            f\"No v2 client for {provider} (model {model}). \"\n            f\"Supported: {', '.join(sorted(SUPPORTED_PROVIDERS))}.\"\n        )\n\n    api_key = _require_key(provider)\n\n    if provider == \"Anthropic\":\n        from langchain_anthropic import ChatAnthropic\n        chat = ChatAnthropic(model=model, api_key=api_key, timeout=timeout,\n                             max_retries=1, max_tokens=max_tokens)\n    elif provider == \"OpenAI\":\n        from langchain_openai import ChatOpenAI\n        chat = ChatOpenAI(model=model, api_key=api_key, timeout=timeout,\n                          max_retries=1, base_url=os.getenv(\"OPENAI_API_BASE\"))\n    elif provider == \"DeepSeek\":\n        from langchain_deepseek import ChatDeepSeek\n        chat = ChatDeepSeek(model=model, api_key=api_key, timeout=timeout,\n                            max_retries=1)","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/virattt/ai-hedge-fund/blob/eff8a7320fcf0b473b135690fa1a5b0d9b022a83/hedge_fund/llm/client.py#L87-L123","documentation":"Raised by make_llm (hedge_fund/llm/client.py:105) when the resolved provider has no v2 chat client implementation. The provider comes from provider_for(model) — unlisted model ids default to Anthropic — and is checked against SUPPORTED_PROVIDERS (Anthropic, OpenAI, xAI, DeepSeek, Google, Kimi). Since the supported set currently equals the whole registry, hitting this means provider_for returned something unexpected (or the registry grew without a transport).","triggerScenarios":"Setting HEDGE_FUND_LLM_MODEL (or passing model=) to an id that provider_for maps to a provider not in {Anthropic, OpenAI, xAI, DeepSeek, Google, Kimi}; a custom/extended registry entry added without a corresponding client branch in make_llm; a TUI picker selection of a provider row that is shown but not backed by a transport (the registry comment notes such rows should be non-selectable).","commonSituations":"New model id added to the registry file before the transport existed; HEDGE_FUND_LLM_MODEL left over from a fork that supported a provider (e.g. 'Mistral') this build doesn't; env var pointing at a typo'd model string that maps oddly.","solutions":["Set HEDGE_FUND_LLM_MODEL to a known model (default 'claude-sonnet-5') or pass model= explicitly with a supported id from the registry.","If you need the unsupported provider, add the langchain transport branch for it in make_llm and ensure it's in PROVIDER_ENV_VARS/SUPPORTED_PROVIDERS — then the check passes.","Inspect provider_for(model) for your exact id to see which provider it resolves to; the error names both provider and model."],"exampleFix":"# before\nos.environ[\"HEDGE_FUND_LLM_MODEL\"] = \"mistral-large\"\nchat = make_llm()  # ValueError: No v2 client for ...\n\n# after\nos.environ[\"HEDGE_FUND_LLM_MODEL\"] = \"claude-sonnet-5\"\nchat = make_llm()","handlingStrategy":"validation","validationCode":"from hedge_fund.llm.registry import SUPPORTED_PROVIDERS, provider_for\n\ndef model_is_runnable(model_id: str) -> bool:\n    provider = provider_for(model_id) or \"Anthropic\"  # same default as make_llm\n    return provider in SUPPORTED_PROVIDERS","typeGuard":"from hedge_fund.llm.registry import SUPPORTED_PROVIDERS, provider_for\n\ndef resolves_to_supported_provider(model_id: str) -> bool:\n    p = provider_for(model_id)\n    return (p or \"Anthropic\") in SUPPORTED_PROVIDERS","tryCatchPattern":"try:\n    chat = make_llm(model=model_id)\nexcept ValueError as e:\n    if \"No v2 client\" in str(e):\n        raise SystemExit(\n            f\"model {model_id!r} has no transport; pick one of the registry models\"\n        ) from e\n    raise","preventionTips":["Set HEDGE_FUND_LLM_MODEL to an id from the shipped registry rather than free-typing ids.","Validate the model id against provider_for()/SUPPORTED_PROVIDERS at app startup, not at first LLM call.","After upgrading, re-run any smoke test that constructs the LLM — registries and transports drift together."],"tags":["llm","config","provider","env"],"backgroundTag":null,"analyzedSha":"eff8a7320fcf0b473b135690fa1a5b0d9b022a83","analyzedAt":"2026-08-15T00:22:46.567Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}