ANTIGRAVITY LABJP
Articles/Antigravity Basics
Antigravity Basics/2026-05-23Intermediate

Why Antigravity's AI Agent Misreads .env Values — Quoting, Whitespace, and Export Pitfalls

When Antigravity's agent writes or reads .env files, subtle differences in quoting, trailing whitespace, export prefixes, and # characters cause silent value corruption. Here are four real cases I hit in production, with concrete diagnostics and fixes.

antigravity429dotenv2environment-variablestroubleshooting105agent17

"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 export prefix 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 value

Fix

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 value

Diagnosing 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:]]+$//' .env

For 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/app

Shells 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 name

Fix

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 +a

Pattern 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 dropped

Node 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-linter

Since 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.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Antigravity2026-05-25
Why Antigravity Agents Hang on ssh, sudo, and git rebase -i — Diagnosing and Permanently Fixing the Missing TTY Problem
When you ask an Antigravity agent to deploy, the terminal panel stops on 'password:' and never moves. The agent isn't broken — the shell behind it has no PTY, so interactive prompts have no one to answer them. Here's how to diagnose and remove every interactive command from your agent workflow.
Antigravity2026-05-31
Why Your Antigravity Agent Stops Mid-Task with 429 RESOURCE_EXHAUSTED, and How to Fix It
When you hand a long task to an Antigravity agent, it sometimes halts halfway with a red 429 RESOURCE_EXHAUSTED. That is a rate-limit or quota signal, not a bug. Here is how I diagnose the three flavors of 429 in production, and how to keep your agent from stalling on the same wall twice.
Antigravity2026-05-28
Fixing Antigravity Google Sign-in That Won't Return From the Browser
When you press Sign in with Google in Antigravity and the browser just hangs without returning to the editor, the cause is rarely a single thing. Here is how I narrow it down across four layers — callback port, third-party cookies, stale session files, and network path — using only commands I keep close on every machine.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →