You hand a refactor to your agent, step away, and come back to find the task frozen at the halfway point with 429 RESOURCE_EXHAUSTED glowing red in the log. The more you lean on Antigravity as a truly autonomous agent, the more often you meet this moment. In my own setup I run content pipelines for four technical blogs, and on days when I scheduled the runs too close together, those 429s cascaded and a couple of jobs quietly finished doing nothing at all.
This error is not a syntax slip or a logic bug. It means the requests (or tokens) you sent to the model in a short window crossed your allotted ceiling. The cause is simple, but the agent won't tell you whether it should "just wait and recover" or "change a setting," so it tends to sit there stalled. Below is the triage I use in real operation, plus the durable fixes that keep you from stopping at the same spot twice.
There are three kinds of "429" — identify yours first
429 RESOURCE_EXHAUSTED looks like one error, but the message body splits into three causes. Skip this step and you'll apply the wrong fix.
- RPM exceeded (requests per minute): the agent fired many tool calls in a short burst. Waiting a few dozen seconds clears it.
- TPM exceeded (tokens per minute): you sent a huge file or a long context all at once. You need to reduce the context itself.
- RPD / daily quota exceeded (per-day ceiling): you ran the agent all day on a free tier. Waiting won't recover it that day — you need to change tiers.
To tell them apart, read the quotaMetric and quotaValue in the error response. If it ends in ...PerMinutePerProject it's per-minute; if ...PerDay, it's daily. Antigravity often collapses this in the agent log, so expand the output panel and read the raw text.
First move: let it auto-retry with exponential backoff
If a per-minute ceiling (RPM / TPM) is the cause, simply waiting and resending solves it. The catch is that naive retries use a fixed delay and keep getting bounced when the API is busy. What works in practice is exponential backoff that prefers the server's recommended wait (RetryInfo) when present.
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
async function generateWithBackoff(
prompt: string,
maxRetries = 5
): Promise<string> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const res = await ai.models.generateContent({
model: "gemini-2.5-pro",
contents: prompt,
});
return res.text ?? "";
} catch (err: any) {
const status = err?.status ?? err?.code;
if (status !== 429 || attempt === maxRetries) throw err;
// Prefer the server's recommended wait, if it gave one.
const retryInfo = err?.details?.find(
(d: any) => d["@type"]?.includes("RetryInfo")
);
const serverDelay = retryInfo?.retryDelay
? parseFloat(retryInfo.retryDelay) * 1000
: 0;
// Exponential backoff + jitter (avoid synchronized retries colliding).
const backoff = Math.min(2 ** attempt * 1000, 32_000);
const jitter = Math.random() * 1000;
const wait = Math.max(serverDelay, backoff) + jitter;
console.warn(`429 detected. Waiting ${Math.round(wait)}ms before retry (attempt ${attempt + 1})`);
await new Promise((r) => setTimeout(r, wait));
}
}
throw new Error("Exhausted maximum retries");
}Two things matter here. First, honor RetryInfo.retryDelay above everything else. When the server explicitly says "wait N more seconds," resending sooner will reliably get bounced again. Second, the jitter. When several agents or batches all recover at the same instant, they collide again and regenerate the 429. A small random spread in the wait time visibly cuts down those re-collisions.
When TPM is the cause: trim the context you send
If waiting doesn't help and the error points at ...TokensPerMinute, your per-request token count is too high. Antigravity agents are generous about pulling related files into context, so on a large repo you cross this ceiling without realizing it.
The effective move is to physically narrow what reaches the agent. Use .antigravityignore to exclude build artifacts, logs, and large generated files, and with @ references point at the specific files you need rather than a whole folder. In my case, excluding dist/, .next/, *.log, and some large snapshot JSON was enough to make the mid-task 429s nearly disappear. More context isn't better — keeping it to the minimum the agent actually needs improves both accuracy and stability.
# Example .antigravityignore
node_modules/
dist/
.next/
*.log
coverage/
*.snapshot.json
public/content/
When it's the daily quota: waiting won't save you
If the error points at ...PerDay, or the agent suddenly dies in the evening after running all day, you've drained your daily quota. Waiting won't bring it back that day. You have three options:
- Move to a paid tier: free-tier daily limits are quite low for some models. If you run agents continuously, this is the realistic answer.
- Match the model to the job: you don't need the top model for every step. Routing code generation to a high-capability model and summaries or classification to a lighter one changes quota burn dramatically.
- Spread runs over time: if you use scheduled jobs or batches, don't cluster them in the same window. I deliberately stagger the update tasks for my four sites across different times so they don't hit the per-minute and daily ceilings simultaneously.
Prevention: let the agent run on good terms with the limits
Recovery is only half the story; designing so you rarely hit 429 matters too. Three habits I keep: First, build backoff-and-retry into autonomous tasks from the start — assuming failure is easier to operate than bolting it on later. Second, don't get greedy with concurrency. Capping simultaneous agents or requests at one or two prevents a lot of RPM overruns. Third, slice long tasks small. Breaking one request into per-file or per-feature units lowers tokens per request and makes a stalled task easy to resume.
I've been building apps solo since 2014, so I've had a long relationship with external API rate limits. With AI agents the essence turns out to be the same: read the limit, wait, and spread the load, and most 429s quietly fade away.
When a 429 shows up, just check the quotaMetric in the error body once. Once you know whether it's per-minute or daily, deciding whether to wait or change a setting becomes surprisingly easy.