env-var-hygiene

Environment Variable Hygiene

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "env-var-hygiene" with this command: npx skills add phrazzld/claude-config/phrazzld-claude-config-env-var-hygiene

Environment Variable Hygiene

Best practices for managing environment variables across deployment platforms.

Triggers

Invoke when user mentions:

  • "env var", "environment variable", "production deploy"

  • "webhook secret", "API key", "token"

  • "Invalid character in header", "ERR_INVALID_CHAR"

  • "silent failure", "webhook not working"

  • "Vercel", "Convex", "deployment", "secrets"

Core Principles

  1. Trailing Whitespace Kills

Env vars with \n or trailing spaces cause cryptic errors:

  • "Invalid character in header content" (HTTP headers)

  • Webhook signature mismatch

  • Silent authentication failures

Root Cause: Copy-paste or echo introduces invisible characters.

Prevention:

✅ Use printf, not echo

printf '%s' 'sk_live_xxx' | vercel env add STRIPE_SECRET_KEY production

✅ Trim when setting

bunx convex env set --prod KEY "$(echo 'value' | tr -d '\n')" # or: npx convex ...

❌ Don't use echo directly

echo "sk_live_xxx" | vercel env add KEY production # May add \n

  1. Cross-Platform Parity

Shared tokens (webhook secrets, auth tokens) must be identical across platforms:

  • Vercel ↔ Convex

  • Frontend ↔ Backend

  • Dev ↔ Staging ↔ Prod (within each platform)

Common Pitfall: Set token on one platform, forget the other.

Prevention:

Generate token once

TOKEN=$(openssl rand -hex 32)

Set on ALL platforms

bunx convex env set --prod CONVEX_WEBHOOK_TOKEN "$(printf '%s' "$TOKEN")" # or: npx convex ... printf '%s' "$TOKEN" | vercel env add CONVEX_WEBHOOK_TOKEN production

  1. Validate Format Before Use

API keys have specific formats. Validate before deployment:

Service Pattern Example

Stripe Secret sk_(test|live)_[A-Za-z0-9]+

sk_live_xxx

Stripe Public pk_(test|live)_[A-Za-z0-9]+

pk_live_xxx

Stripe Webhook whsec_[A-Za-z0-9]+

whsec_xxx

Stripe Price price_[A-Za-z0-9]+

price_xxx

Clerk Secret sk_(test|live)_[A-Za-z0-9]+

sk_live_xxx

  1. Dev ≠ Prod

Separate deployments have separate env var stores:

  • Setting .env.local doesn't affect production

  • Convex dev and prod are separate deployments

  • Vercel has per-environment variables

Always verify prod separately:

Convex

bunx convex env list --prod # or: npx convex ...

Vercel

vercel env ls --environment=production

  1. CLI Environment Gotcha

CONVEX_DEPLOYMENT=prod:xxx npx convex data may return dev data.

Always use explicit flags:

❌ Unreliable

CONVEX_DEPLOYMENT=prod:xxx npx convex data

✅ Reliable

bunx convex run --prod module:function # or: npx convex ... bunx convex env list --prod

  1. Env Load Semantics (Restart Required)

Many runtimes load .env.local once at process start.

If code logs "missing X" but .env.local has X:

  • you edited .env.local after server started. Restart dev server.

  • your shell env overrides dotenv (incl empty string): printenv KEY then unset KEY .

Quick Reference

Setting Env Vars Safely

Convex:

Dev

bunx convex env set KEY "value" # or: npx convex ...

Prod (use --prod flag)

bunx convex env set --prod KEY "$(printf '%s' 'value')"

Vercel:

Production

printf '%s' 'value' | vercel env add KEY production

With explicit environment

vercel env add KEY production --force

Checking Env Vars

Convex:

bunx convex env list # dev bunx convex env list --prod # prod

Vercel:

vercel env ls # all vercel env ls --environment=production # prod only

Detecting Issues

Trailing whitespace:

Check Convex prod

bunx convex env list --prod | while IFS= read -r line; do if [[ "$line" =~ [[:space:]]$ ]]; then echo "WARNING: $(echo "$line" | cut -d= -f1) has trailing whitespace" fi done

Format validation:

Validate Stripe key format

value=$(bunx convex env list --prod | grep "^STRIPE_SECRET_KEY=" | cut -d= -f2-) [[ "$value" =~ ^sk_(test|live)_[A-Za-z0-9]+$ ]] || echo "Invalid format"

References

See references/ directory:

  • format-patterns.md

  • Regex patterns for common services

  • platform-specifics.md

  • Vercel, Convex, Railway platform details

  • hygiene-checklist.md

  • Pre-deployment validation checklist

  • parity-verification.md

  • Cross-platform token verification

Related Commands

  • /pre-deploy

  • Comprehensive pre-deployment checklist

  • /env-parity-check

  • Cross-platform token verification

  • /stripe-check

  • Stripe-specific environment audit

Based on 2026-01-17 incident: Trailing \n in STRIPE_SECRET_KEY caused "Invalid character in header" error. Token mismatch between Vercel and Convex caused silent webhook failures.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

pencil-renderer

No summary provided by upstream source.

Repository SourceNeeds Review
General

ui-skills

No summary provided by upstream source.

Repository SourceNeeds Review
General

llm-gateway-routing

No summary provided by upstream source.

Repository SourceNeeds Review
General

documentation-standards

No summary provided by upstream source.

Repository SourceNeeds Review