virattt/ai-hedge-fund · error · ValueError

{env_var} not found. Set it in your .env to use {provider} m

Error message

{env_var} not found. Set it in your .env to use {provider} models.

What it means

Raised by _require_key (hedge_fund/llm/client.py:184) when the provider's API key environment variable is unset or empty. The error deliberately names the exact variable (ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, DEEPSEEK_API_KEY, GOOGLE_API_KEY, KIMI_API_KEY — Kimi also accepts MOONSHOT_API_KEY) because that is the only actionable item for the user.

Source

Thrown at hedge_fund/llm/client.py:184

    if isinstance(content, list):
        parts = []
        for block in content:
            if isinstance(block, str):
                parts.append(block)
            elif isinstance(block, dict) and block.get("type") == "text":
                parts.append(block.get("text", ""))
        return sep.join(parts)
    return "" if content is None else str(content)


def _require_key(provider: str) -> str:
    """The provider's API key, or a failure that names the variable to set."""
    env_var = env_var_for(provider)
    # Kimi accepts either name; v1 reads MOONSHOT_API_KEY first.
    key = (os.getenv("MOONSHOT_API_KEY") if provider == "Kimi" else None)
    key = key or (os.getenv(env_var) if env_var else None)
    if not key:
        raise ValueError(
            f"{env_var} not found. Set it in your .env to use {provider} models."
        )
    return key


def extract_json(text: str) -> dict:
    """Pull the first JSON object out of an LLM response.

    Tries: ```json fence -> whole string -> first balanced {...} block.
    Raises LLMParseError if nothing parses.
    """
    fence = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", text, re.DOTALL)
    if fence:
        try:
            return json.loads(fence.group(1))
        except json.JSONDecodeError:
            pass

View on GitHub (pinned to eff8a7320f)

Solutions

  1. Add the exact variable named in the message to your .env (e.g. ANTHROPIC_API_KEY=sk-ant-...) and restart the process so it's reloaded.
  2. If the .env exists but isn't picked up, verify it's on the loader's path (cwd / dotenv config) or export the variable in the shell.
  3. For Kimi specifically, either KIMI_API_KEY or MOONSHOT_API_KEY works — set whichever you have.

Example fix

# before
# .env missing key -> ValueError: ANTHROPIC_API_KEY not found. Set it in your .env to use Anthropic models.

# after
# .env
ANTHROPIC_API_KEY=sk-ant-your-key-here
Defensive patterns

Strategy: validation

Validate before calling

from hedge_fund.llm.registry import PROVIDER_ENV_VARS, provider_for

def key_is_set(model_id: str) -> bool:
    provider = provider_for(model_id) or "Anthropic"
    env_var = PROVIDER_ENV_VARS[provider]
    import os
    if provider == "Kimi":
        return bool(os.getenv("KIMI_API_KEY") or os.getenv("MOONSHOT_API_KEY"))
    return bool(os.getenv(env_var))

Type guard

import os
from hedge_fund.llm.registry import PROVIDER_ENV_VARS

def provider_key_present(provider: str) -> bool:
    env_var = PROVIDER_ENV_VARS.get(provider)
    if env_var is None:
        return False
    if provider == "Kimi":
        return bool(os.getenv("MOONSHOT_API_KEY") or os.getenv(env_var))
    return bool(os.getenv(env_var))

Try / catch

try:
    chat = make_llm()
except ValueError as e:
    if "not found. Set it in your .env" in str(e):
        raise SystemExit(str(e)) from e  # message already names the variable
    raise

Prevention

When it happens

Trigger: Calling make_llm() (directly or via an LLM-agent signal) with no .env loaded: no ANTHROPIC_API_KEY when defaulting to claude-sonnet-5; selecting a DeepSeek or Google model in the TUI without its key set; key present but empty string. Note Kimi has a two-name fallback (MOONSHOT_API_KEY then KIMI_API_KEY); all other providers check exactly one variable.

Common situations: Fresh clone without copying .env.example; .env file exists but the process wasn't started in a directory where it's loaded, or the key line is commented out; CI runner missing the secret; typo in the variable name (e.g. ANTHROPIC_KEY).

Related errors


AI-assisted analysis of virattt/ai-hedge-fund@eff8a7320f (2026-08-15). Data as JSON: /api/errors/46cf29f0d1bff701. Report an issue: GitHub.