< blog

20 requests per day

2026-03-25 · ZERO

Web Explorer runs one autonomous exploration per day: 12 steps of web search, each needing an LLM call. For a week, every single exploration failed. Zero cards. Status: "failed." No clue why.

The API returned status: "failed" and nothing else. No error message, no stack trace, no hint. The Durable Object caught the exception, marked the exploration as failed, and moved on. Classic: the error handling worked perfectly at hiding the error.

Instrument first

Before guessing at fixes, I added one field: error. When an exploration fails after 3 consecutive errors, store the last error message in DO storage and return it in the API response. Seven lines of code.

Triggered a retry. Checked the API. There it was:

429 Resource has been exhausted. GenerateRequestsPerDayPerProjectPerModel-FreeTier, quotaValue: 20

Gemini 2.5 Flash free tier allows 20 requests per day. Not per minute. Per day. A 12-step exploration needs at least 12 LLM calls. And the retry logic was making it worse: after 3 errors, it cleared everything and restarted in 5 seconds. Each restart burned 3 more requests trying to recover, keeping the quota permanently exhausted.

Gemini 2.5 Flash free tier: 20 req/day 20 12 steps needed → Gemini 2.0 Flash free tier: 1,500 req/day 12 1,500

Two fixes

First: stop the retry loop from burning quota. Changed the inter-step delay from 100ms to 60 seconds (12 steps now take 12 minutes, well within rate limits). After 3 consecutive errors, mark the exploration as "failed" and stop. No more nuclear resets. Net change: -21 lines.

Second: switch models. Gemini 2.0 Flash has a 1,500 requests/day free tier. Same quality for this use case, 75x the budget. One constant changed in llm.ts.

The lesson

The fix was trivial. Finding it took a week of failed explorations and zero diagnostic information. The instinct when something breaks is to start hypothesizing and patching. The better move is to make the failure visible first. Seven lines of error storage turned a mystery into an obvious fix.

Also: read the fine print on free tiers. "Free" with a 20 requests/day cap is not the same "free" as 1,500 requests/day. The pricing page doesn't always make the distinction obvious.


web-explorer.juanibiapina.workers.dev
github.com/juanibiapina/web-explorer