{"record":{"id":"3702baf4a6c2fc2b","repo":"datawhalechina/hello-agents","slug":"llm-api-key-env","errorCode":null,"errorMessage":"LLM_API_KEY 仍是占位符，请在 .env 中填写真实密钥","messagePattern":"LLM_API_KEY 仍是占位符，请在 \\.env 中填写真实密钥","errorType":"exception","errorClass":"ConfigurationError","httpStatus":null,"severity":"critical","filePath":"Co-creation-projects/zenith191-RequirementClarifierAgent/src/config.py","lineNumber":76,"sourceCode":"        \"\"\"拒绝缺失、占位符或越界配置。\"\"\"\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":58,"sourceCodeEnd":81,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/zenith191-RequirementClarifierAgent/src/config.py#L58-L81","documentation":"Raised by LLMSettings validation when LLM_API_KEY still holds a known placeholder value. The check casefolds the key and rejects anything starting with 'your_' or exactly equal to 'changeme'/'replace_me'. This prevents shipping an app that authenticates with a template key and gets 401s from the provider.","triggerScenarios":"Leaving LLM_API_KEY=your_api_key_here (or changeme / replace_me, any casing) in .env, then constructing the settings object.","commonSituations":"User copied .env.example verbatim and only filled in some fields; placeholder left in a deployed container's env; examples/templates reused as real config.","solutions":["Obtain a real API key from the provider and set LLM_API_KEY to it in .env.","Make sure you edited the .env actually loaded by the app (check cwd / dotenv path), not a stray copy.","If templating deployments, add a startup check or CI lint that fails builds still containing placeholder keys."],"exampleFix":"# .env before\nLLM_API_KEY=your_api_key_here\n\n# .env after\nLLM_API_KEY=sk-proj-xxxxxxxxxxxxxxxx","handlingStrategy":"validation","validationCode":"import os\n\nkey = os.getenv(\"LLM_API_KEY\", \"\")\nplaceholders = {\"changeme\", \"replace_me\"}\nif not key or key.casefold().startswith(\"your_\") or key.casefold() in placeholders:\n    raise SystemExit(\"LLM_API_KEY is unset or still a placeholder — set a real key\")","typeGuard":null,"tryCatchPattern":"try:\n    settings = LLMSettings.from_env()\nexcept ConfigurationError as e:\n    if \"占位符\" in str(e):\n        sys.exit(\"Fill in a real LLM_API_KEY before running\")\n    raise","preventionTips":["Treat placeholder checks as a deployment gate: run them in a pre-deploy hook.","Secrets managers beat .env for real deployments; use them past local dev.","Add a lint that greps .env files for 'your_', 'changeme', 'replace_me' in CI."],"tags":["python","configuration","secrets","placeholder"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}