{
  "id": "ai-forgets-env-validation",
  "type": "failures",
  "category": "failures",
  "locale": "zh",
  "url": "/zh/failures/ai-forgets-env-validation",
  "title": "如何修复AI忘记环境变量验证",
  "description": "AI代理直接读取process.env值而不进行验证，在环境变量缺失时导致静默的undefined错误，并且缺少启动时的错误提示。",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "Next.js",
    "TypeScript",
    "Cloudflare"
  ],
  "tags": [
    "security",
    "typescript",
    "cloudflare"
  ],
  "difficulty": null,
  "updated": "2026-06-08",
  "markdown": "代理直接访问 `process.env.SOME_KEY`，因此当变量缺失时，应用会在静默状态下启动并出错 — 没有崩溃，没有警告，只是`undefined`流入业务逻辑。\n\n## 症状\n\n原始的`process.env`读取分散在代码库中，没有模式、类型安全或启动时的断言。\n\n```ts\n// lib/stripe.ts — WRONG\nimport Stripe from \"stripe\";\n\nexport const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {\n  apiVersion: \"2024-06-20\",\n});\n// If STRIPE_SECRET_KEY is undefined, Stripe SDK accepts it and every\n// charge silently fails at runtime instead of at startup.\n```\n\n## 发生原因\n\n代理为了简洁和快速达到可用代码而优化。环境变量验证是样板代码，在大多数训练示例中并不出现，因此模型会跳过它直接进行集成。\n\n## 如何识别\n\n- `process.env.FOO`在使用时没有非空断言或回退检查。\n- 项目中不存在`env.ts` / `env.mjs`验证文件。\n- 在调用处，环境变量值的TypeScript类型为`string | undefined`。\n- 即使`.env.local`为空，应用也能无错误启动。\n\n## 如何修复\n\n使用Zod模式在启动时验证所有必需的环境变量，这样进程在服务任何请求之前就会以清晰的错误信息崩溃。\n\n```ts\n// lib/env.ts — CORRECT\nimport { z } from \"zod\";\n\nconst envSchema = z.object({\n  STRIPE_SECRET_KEY: z.string().min(1),\n  DATABASE_URL: z.string().url(),\n  NEXTAUTH_SECRET: z.string().min(32),\n  NODE_ENV: z.enum([\"development\", \"production\", \"test\"]).default(\"development\"),\n});\n\nexport const env = envSchema.parse(process.env);\n//                             ^^^^^ throws at startup if any var is missing\n```\n\n```ts\n// lib/stripe.ts — CORRECT (import validated env)\nimport Stripe from \"stripe\";\nimport { env } from \"@/lib/env\";\n\nexport const stripe = new Stripe(env.STRIPE_SECRET_KEY, {\n  apiVersion: \"2024-06-20\",\n});\n```\n\n```txt\n[ ] Create lib/env.ts with a Zod schema covering every required variable\n[ ] Import env from lib/env everywhere — never use process.env directly\n[ ] Add lib/env.ts to the module graph so it runs at server startup (import in next.config.ts)\n[ ] Document all variables in .env.example with placeholder values\n[ ] Use z.string().url() / z.string().min(n) for format constraints, not just presence\n```\n\n## 修复提示\n\n```txt title=\"Fix Prompt\"\nEvery raw process.env access in this file is unvalidated. Create a lib/env.ts\nmodule that parses and validates all required environment variables with Zod at\nstartup. Replace every process.env.FOO reference in the codebase with the\ntyped env.FOO import. Add a .env.example file listing every variable with a\nplaceholder value and comment.\n```\n\n## 测试\n\n```bash\n# Find any remaining raw process.env reads outside of lib/env.ts\ngrep -rn \"process\\.env\\.\" --include=\"*.ts\" --include=\"*.tsx\" . \\\n  | grep -v \"lib/env.ts\" \\\n  | grep -v \"next.config\" \\\n  | grep -v \"node_modules\" \\\n  && echo \"FAIL: raw process.env reads found\" || echo \"OK\"\n```"
}