Vercel Logo

Fail fast on misconfiguration, not during production

Missing env vars cause runtime errors deep in the stack instead of failing at boot. "not_authed" at request time when the real issue is a missing token at startup. Boot checks catch these instantly before any code runs.

After this lesson, you'll:

  • Remove an env var → app fails instantly with clear error message
  • See Environment validation failed instead of cryptic runtime errors
  • Get type-safe autocomplete for env.SLACK_BOT_TOKEN throughout your code
# ❌ Before boot checks (confusing):
$ slack run
[ERROR] UnhandledPromiseRejectionWarning: Error: An API error occurred: not_authed
    at validateToken (node_modules/@slack/web-api/dist/WebClient.js:789:23)
 
# ✅ After boot checks (explicit):
$ slack run
Invalid environment configuration: [{
  "path": ["SLACK_BOT_TOKEN"],
  "message": "SLACK_BOT_TOKEN is required"
}]
Error: Environment validation failed

Outcome

Harden the repo so it fails fast on environment misconfigurations, missing secrets, and also confirms AI connectivity.

Fast Track

  1. Create server/env.ts with Zod schema for required env vars
  2. Import at top of app.ts to validate on boot
  3. Test by removing an env var and confirming fail-fast behavior

Using Zod for env validation

Why Zod?

Zod is a TypeScript-first schema validation library. You define what data should look like, and Zod validates it at runtime while providing type safety. You'll use the pattern of defining a schema → safeParse() → handle success/errors throughout the course.

Create server/env.ts to validate required environment variables at boot:

/server/env.ts
import { z } from "zod";
 
export const envSchema = z.object({
  SLACK_SIGNING_SECRET: z.string().min(1, "SLACK_SIGNING_SECRET is required"),
  SLACK_BOT_TOKEN: z.string().min(1, "SLACK_BOT_TOKEN is required"),
  // AI gateway auth can come from an explicit API key or from Vercel's OIDC integration.
  // We don't hard-require either here to keep boot checks focused on Slack secrets.
  AI_GATEWAY_API_KEY: z.string().optional(),
  NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
});
 
const result = envSchema.safeParse(process.env);
 
if (!result.success) {
  console.error("Invalid environment configuration:", result.error.issues);
  throw new Error("Environment validation failed");
}
 
export const env = result.data;

Import the env module at the top of server/app.ts to fail fast during startup. Replace all process.env.* references with env.*:

/server/app.ts
import { App, LogLevel } from "@slack/bolt";
import { VercelReceiver } from "@vercel/slack-bolt";
import registerListeners from "./listeners";
import { env } from "./env";
 
const logLevel =
  env.NODE_ENV === "development" ? LogLevel.DEBUG : LogLevel.INFO;
 
const receiver = new VercelReceiver({
  logLevel,
});
 
const app = new App({
  token: env.SLACK_BOT_TOKEN,
  signingSecret: env.SLACK_SIGNING_SECRET,
  receiver,
  deferInitialization: true,
  logLevel,
});
 
registerListeners(app);
 
export { app, receiver };

Note: You'll also need to update any other files that reference process.env.SLACK_BOT_TOKEN, process.env.SLACK_SIGNING_SECRET, or process.env.AI_GATEWAY_API_KEY to use the env object instead. The main touchpoint is server/app.ts, but check listeners and utilities if you added direct process.env references elsewhere.

Try It

  1. Test fail-fast behavior:

    • Comment out SLACK_BOT_TOKEN in .env
    • Run slack run — it should fail immediately with:
      Invalid environment configuration: [
        {
          "path": ["SLACK_BOT_TOKEN"],
          "message": "SLACK_BOT_TOKEN is required"
        }
      ]
      Error: Environment validation failed
      
  2. Restore and verify:

    • Uncomment SLACK_BOT_TOKEN
    • Run slack run — app starts successfully

Commit

git add -A
git commit -m "feat(boot): add environment validation with Zod
 
- Create env.ts with required variable schema
- Fail fast on missing or invalid configuration
- Type-safe environment variable access throughout app"

Done-When

  • Created server/env.ts with Zod validation schema
  • App fails immediately when required env vars are missing
  • Type-safe access to environment variables via env object