{"record":{"id":"3500433d8bce1e28","repo":"datawhalechina/hello-agents","slug":"llm-missing-env","errorCode":null,"errorMessage":"缺少 LLM 配置：{missing}。请先复制并填写 .env。","messagePattern":"缺少 LLM 配置：(.+?)。请先复制并填写 \\.env。","errorType":"exception","errorClass":"ConfigurationError","httpStatus":null,"severity":"critical","filePath":"Co-creation-projects/zenith191-RequirementClarifierAgent/src/config.py","lineNumber":70,"sourceCode":"            timeout=_read_int(\"LLM_TIMEOUT\", 120),\n        )\n        settings.validate()\n        return settings\n\n    def validate(self) -> None:\n        \"\"\"拒绝缺失、占位符或越界配置。\"\"\"\n\n        missing = [\n            name\n            for name, value in (\n                (\"LLM_MODEL_ID\", self.model),\n                (\"LLM_API_KEY\", self.api_key),\n                (\"LLM_BASE_URL\", self.base_url),\n            )\n            if not value\n        ]\n        if missing:\n            raise ConfigurationError(\n                \"缺少 LLM 配置：\" + \", \".join(missing) + \"。请先复制并填写 .env。\"\n            )\n\n        lowered_key = self.api_key.casefold()\n        if lowered_key.startswith(\"your_\") or lowered_key in {\"changeme\", \"replace_me\"}:\n            raise ConfigurationError(\"LLM_API_KEY 仍是占位符，请在 .env 中填写真实密钥\")\n        if not 0 <= self.temperature <= 2:\n            raise ConfigurationError(\"LLM_TEMPERATURE 必须位于 0 到 2 之间\")\n        if self.timeout <= 0:\n            raise ConfigurationError(\"LLM_TIMEOUT 必须大于 0\")\n","sourceCodeStart":52,"sourceCodeEnd":81,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/zenith191-RequirementClarifierAgent/src/config.py#L52-L81","documentation":"Raised by LLMSettings validation (src/config.py:70) when one or more of LLM_MODEL_ID, LLM_API_KEY, LLM_BASE_URL are empty/None. The message names the missing keys so you know exactly which required fields were not provided. It is a fail-fast guard meant to stop startup before an LLM client is constructed with unusable config.","triggerScenarios":"Building LLMSettings (or calling from_env) with an empty-string api_key, a missing base_url, or before copying .env.example to .env. Any falsy value among the three required fields triggers it.","commonSituations":"Fresh clone without running the 'cp .env.example .env' step; .env exists but is not loaded (running from a different cwd, or python-dotenv not invoked); CI pipeline where secrets were never added; a key was commented out in .env.","solutions":["Copy the template: cp .env.example .env and fill in LLM_MODEL_ID, LLM_API_KEY, LLM_BASE_URL.","Confirm the .env file is actually loaded at startup (dotenv.load_dotenv() called, correct path).","In CI, add the three variables as repository secrets/environment variables.","Re-run and confirm the missing list in the message is now empty."],"exampleFix":"# before: .env missing\n# (LLM_MODEL_ID not set at all)\n\n# after: .env\nLLM_MODEL_ID=gpt-4o-mini\nLLM_API_KEY=sk-...\nLLM_BASE_URL=https://api.openai.com/v1","handlingStrategy":"validation","validationCode":"import os\n\nREQUIRED = (\"LLM_MODEL_ID\", \"LLM_API_KEY\", \"LLM_BASE_URL\")\nmissing = [k for k in REQUIRED if not (os.getenv(k) or \"\").strip()]\nif missing:\n    raise SystemExit(f\"Missing env: {', '.join(missing)} — copy .env.example to .env\")","typeGuard":null,"tryCatchPattern":"try:\n    settings = LLMSettings.from_env()\nexcept ConfigurationError as e:\n    print(f\"Setup incomplete: {e}\")\n    print(\"Run: cp .env.example .env && edit it\")\n    sys.exit(2)","preventionTips":["Ship a .env.example and a setup check in README step 1.","Add CI jobs that fail when required LLM_* vars are absent from the secret store.","Call dotenv.load_dotenv() explicitly with a resolved path at app entry."],"tags":["python","configuration","setup","environment-variables"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}