datawhalechina/hello-agents · critical · ValueError

LLM_MODEL_ID, LLM_API_KEY, and LLM_BASE_URL must be set (via

Error message

LLM_MODEL_ID, LLM_API_KEY, and LLM_BASE_URL must be set (via constructor args or .env file).

What it means

ValueError raised by the LLMClient constructor when any of model, api_key, or base_url is None after checking constructor args and then the LLM_MODEL_ID / LLM_API_KEY / LLM_BASE_URL environment variables (or .env file). It is a fail-fast guard so the OpenAI client is never constructed with unusable credentials.

Source

Thrown at Co-creation-projects/zjzhou-SREOnCallAgent/src/core/llm_client.py:27

class HelloAgentsLLM:
    """OpenAI-compatible LLM client (works with AIHubmix, ModelScope, OpenAI)."""

    def __init__(
        self,
        model: str = None,
        api_key: str = None,
        base_url: str = None,
        timeout: int = None,
        verbose: bool = True,
    ):
        self.model = model or os.getenv("LLM_MODEL_ID")
        api_key = api_key or os.getenv("LLM_API_KEY")
        base_url = base_url or os.getenv("LLM_BASE_URL")
        timeout = timeout or int(os.getenv("LLM_TIMEOUT", "60"))
        self.verbose = verbose

        if not all([self.model, api_key, base_url]):
            raise ValueError(
                "LLM_MODEL_ID, LLM_API_KEY, and LLM_BASE_URL must be set "
                "(via constructor args or .env file)."
            )

        self.client = OpenAI(api_key=api_key, base_url=base_url, timeout=timeout)

    def think(self, messages: List[Dict[str, str]], temperature: float = 0) -> str:
        if self.verbose:
            print(f"🧠 Calling {self.model}...")
        try:
            response = self.client.chat.completions.create(
                model=self.model,
                messages=messages,
                temperature=temperature,
                stream=True,
            )
            collected = []
            for chunk in response:

View on GitHub (pinned to 606a07d341)

Solutions

  1. Create a .env file with LLM_MODEL_ID, LLM_API_KEY, and LLM_BASE_URL set (all three are required)
  2. Ensure load_dotenv() runs before LLMClient is constructed, or export the variables in the shell
  3. Alternatively pass the values explicitly: LLMClient(model='...', api_key='...', base_url='...')
  4. Check for typos in variable names — the constructor does not warn about near-misses

Example fix

# before
client = LLMClient()  # ValueError if env not set

# after
from dotenv import load_dotenv
load_dotenv()  # loads .env with LLM_MODEL_ID / LLM_API_KEY / LLM_BASE_URL
client = LLMClient()
Defensive patterns

Strategy: validation

Validate before calling

import os

def llm_env_ready() -> bool:
    return all([os.getenv('LLM_MODEL_ID'), os.getenv('LLM_API_KEY'), os.getenv('LLM_BASE_URL')])

assert llm_env_ready(), 'Set LLM_MODEL_ID, LLM_API_KEY, LLM_BASE_URL in .env first'

Try / catch

try:
    client = LLMClient()
except ValueError as e:
    if 'LLM_MODEL_ID' in str(e):
        sys.exit('Missing LLM configuration: check .env / load_dotenv()')
    raise

Prevention

When it happens

Trigger: Instantiating LLMClient() with no arguments when the .env file is missing, not loaded (python-dotenv load_dotenv() not called), or lacks one of the three variables; misspelled variable names like LLM_APIKEY; running in a fresh shell/CI where env vars were never exported.

Common situations: Cloning the repo without copying .env.example to .env; forgetting load_dotenv() at program start; CI pipelines with no secrets injected; switching between OpenAI-compatible providers and forgetting to update LLM_BASE_URL.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/7c8d4c2a2bb5d728. Report an issue: GitHub.