"The app starts fine, the agent doesn't throw any errors — but my API key just won't authenticate." If you've spent more than a few hours building with Antigravity, you've probably hit this exact "half-working" state. In my experience, a surprisingly large share of these cases come down to one thing: the AI agent isn't reading your .env file the way you think it is.
Across my own indie app business — where I juggle AdMob, Firebase, and Stripe credentials in .env files for several apps — I hit this pitfall three times in the first week after I moved to Antigravity. A Stripe STRIPE_SECRET_KEY that looked byte-identical to the dashboard kept returning 401s. An AdMob Application ID that was clearly "set" produced not even a test ad. Every case turned out to be a quoting or whitespace mismatch between how the agent wrote the .env and how the runtime library parsed it. This article walks through the four most common patterns I've seen, with diagnostics and permanent fixes for each.
Why Antigravity's Agent in Particular Misreads .env
The .env file format has no formal specification. Implementations in Node.js, Python, Ruby, and Go all disagree slightly on the basics — whether quotes are part of the value or just delimiters, whether the shell-style export prefix is allowed, whether trailing whitespace is trimmed.
Antigravity's AI agent tends to interpret .env files using shell-compatible heuristics when writing code. Meanwhile, the dotenv package that actually runs at startup (require('dotenv').config()) uses its own rules. The gap between "what the agent thinks the value is" and "what the runtime actually sees" creates the worst kind of bug: things start up cleanly, but values are silently wrong.
Here are the four patterns I've personally fallen into, in order of frequency.
- Pattern 1: Double quotes leak into the value
- Pattern 2: Trailing spaces or tabs sneak in
- Pattern 3: The
exportprefix confuses the agent - Pattern 4:
#inside a value gets parsed as a comment
Pattern 1: Double Quotes Leak Into the Value
This is the most frequent one. When you copy a Stripe secret key from the dashboard, you never get quotes — they're just the raw sk_test_... string. But when I asked the agent to "add the Stripe key to my .env," it helpfully wrapped it:
# .env
STRIPE_SECRET_KEY="sk_test_YOUR_PLACEHOLDER_VALUE_HERE"Node.js dotenv v16+ strips these quotes correctly. But the moment you source .env from a shell, or use docker run --env-file .env, the parser changes. Docker's --env-file parser, in particular, treats quotes as part of the value. The container ends up with "sk_test_..." — with literal double quotes wrapping the string. Stripe rejects it with a 401.
Diagnosing It
The fastest way is to print exactly what the runtime sees:
# What does Node see?
node -e "require('dotenv').config(); console.log(JSON.stringify(process.env.STRIPE_SECRET_KEY))"
# Expected: "sk_test_..." (quotes only around the JSON-stringified output)
# What does Docker see?
docker run --rm --env-file .env alpine sh -c 'echo "[$STRIPE_SECRET_KEY]"'
# Expected: [sk_test_...]
# Bug: ["sk_test_..."] ← quotes are inside the valueFix
Adopt a single rule: don't quote values in .env. Only quote when the value contains spaces. Tell your agent the same thing in AGENTS.md, and the generated .env files become predictable.
Pattern 2: Trailing Spaces or Tabs Sneak In
This is the one that cost me the most debugging time. After pasting my AdMob Application ID (ca-app-pub-XXXXXXXXXXXXXXXX~YYYYYYYYYY) into .env, react-native-google-mobile-ads kept returning "invalid application id."
When I finally opened the file in a hex-aware viewer, there was a stray \t (tab) at the end of the line. The agent had added it while "aligning" the file's indentation — a perfectly reasonable formatting impulse that broke the value.
# Looks fine on the surface
ADMOB_APP_ID=ca-app-pub-1234567890123456~1234567890
# Reality: there's a tab character at the end of the valueDiagnosing It
Use cat -A to surface all invisible characters:
cat -A .env | grep ADMOB
# Good: ADMOB_APP_ID=ca-app-pub-1234567890123456~1234567890$
# Bug: ADMOB_APP_ID=ca-app-pub-1234567890123456~1234567890^I$
# (^I is a tab — anything before $ that isn't your value is bad)Fix
Strip trailing whitespace in one shot:
# macOS
sed -i '' -E 's/[[:space:]]+$//' .env
# Linux
sed -i -E 's/[[:space:]]+$//' .envFor permanent prevention, add .editorconfig to the repo with trim_trailing_whitespace = true. The agent's edits will be auto-trimmed on save, and the bug stops recurring.
Pattern 3: The export Prefix Confuses the Agent
If you source .env in shell scripts, you might write:
# .env
export DATABASE_URL=postgres://user:pass@localhost:5432/appShells handle this fine, and dotenv v17+ silently ignores the export keyword. But when Antigravity's agent parses the same file to understand your environment, it has sometimes treated export DATABASE_URL as the variable name itself. I caught this in my own project when the agent started generating Prisma error handling for a missing export DATABASE_URL variable.
Diagnosing It
Grep the generated code for suspicious patterns:
grep -rn "process.env\." src/ | grep -i "export"
# Any hit here means the agent took the export prefix into the variable nameFix
Drop export from .env entirely. If you need shell-loadable env vars, either keep a separate .env.sh, or use set -a; source .env; set +a — that exports every variable in the file without needing the prefix on each line.
# Remove all export prefixes
sed -i.bak -E 's/^export[[:space:]]+//' .env
# .env.bak is your safety net
# Then load in shell
set -a
source .env
set +aPattern 4: # Inside a Value Becomes a Comment
If a Stripe webhook secret or password contains #, some .env parsers treat everything after it as a comment:
# .env
WEBHOOK_SECRET=whsec_abc#def123 # everything after # gets droppedNode dotenv v16+ explicitly truncates on # for unquoted values (per the official behavior). The agent knows this rule but often forgets to add quotes when generating the file.
Fix
For any value that might contain #, $, or \, wrap it in single quotes. Single quotes disable all interpolation and comment parsing:
# .env
WEBHOOK_SECRET='whsec_abc#def123'
PASSWORD='p@ss$word!'Avoid double quotes here — they reactivate $ interpolation and create a different class of bug. For machine-generated secrets, single quotes are the safer default.
How to Keep the Agent From Repeating the Mistake
Fixing each occurrence works, but if the agent keeps generating the same shapes, you'll keep debugging the same bugs. I add the following to AGENTS.md (or .cursorrules) on every project now:
# AGENTS.md (excerpt)
## Rules for editing .env files
1. Do not wrap values in quotes. Use single quotes only when the value contains
spaces, `#`, `$`, or backslashes.
2. Do not prefix lines with `export`. If shell-loadable, use
`set -a; source .env; set +a` instead.
3. No trailing spaces or tabs on any line.
4. After pasting any value, run `cat -A .env | tail -n 1` to verify the line ends cleanly.For belt-and-suspenders protection, drop dotenv-linter into pre-commit. It catches manual edits that slip past the agent's rules:
# .pre-commit-config.yaml
- repo: https://github.com/dotenv-linter/dotenv-linter
rev: v3.3.0
hooks:
- id: dotenv-linterSince putting these in place, .env-related debugging has effectively disappeared from my workflow across multiple production apps.
Wrap-Up
The .env format's lack of a spec is the root cause of all four pitfalls above. AI agents — including Antigravity's — interpret it heuristically, and any disagreement with the runtime library shows up as a silent value mismatch. The single most useful step is to codify the rules in AGENTS.md: no quotes around plain values, single quotes for special characters, no export prefix, no trailing whitespace. That alone removes the "half-works, half-doesn't" debugging trap for good.
Hope this saves someone else the hours it cost me. Thanks for reading.