◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/API & SDK
⬡ API & SDK/2026-10-16Beginner

Sending 40 Rows From Make to the Claude API Stops at Row 14 — Avoiding the 429 With One Subtraction

Why a no-code automation that sends spreadsheet rows to the Claude API one by one hits a 429 partway through, and how to fix it. Seven spacing strategies tested on a mock bucket, a formula for the Sleep delay, and settings that stop failed rows from vanishing.

Makeno-code4295rate limits7Claude API128

It was a night I'd set up a small automation: forty rows in a spreadsheet, each one handed to Claude to tidy up. The rows were store descriptions that needed polishing per language, and I was tired of doing it by hand. I pressed run, watched the modules light up green, and at row 14 the whole thing turned red and stopped.

I keep seeing the same story in no-code communities: "it works for a while, then it just stops." Nothing is broken on Claude's side. You've run into the per-minute limit on requests, and the answer comes back as a 429.

What I'd like to say up front is that the fix is simply to wait. The part worth writing down is that how long to wait isn't a guess. It's a subtraction, and there's one setting that decides whether failed rows get recorded or quietly disappear.

A 429 means "too fast," not "broken"

The Claude API limits requests per minute, plus input and output tokens per minute. Go over, and you get a 429. The response carries a retry-after header with a suggested wait.

How the limit is counted matters too. It isn't "everything resets at the top of the minute." Think of a bucket that refills a little at a time. The first several calls go through, the bucket runs dry, and 429s begin. Row 14 was exactly that moment.

You can check your own limits on the Limits page in the Console. To keep the numbers easy to swap for yours, everything below uses a mock with a limit of 10 requests per minute.

Seven spacing strategies on a mock bucket

This is a mock bucket running in virtual time, not the real API. The limit is 10 requests a minute, the bucket starts full with room for 10 calls, and each call takes 1.5 seconds. There are 40 rows. Because time is simulated, nothing actually waits.

# sim429.py — a mock bucket in virtual time (not the real API)
class Bucket:
    def __init__(self, rpm, cap):
        self.rate = rpm / 60.0      # refill per second
        self.cap = cap              # capacity at the start
        self.tokens = cap
        self.t = 0.0
 
    def take(self, now):
        # refill for the elapsed time, then see if one call fits
        self.tokens = min(self.cap, self.tokens + (now - self.t) * self.rate)
        self.t = now
        if self.tokens >= 1:
            self.tokens -= 1
            return True
        return False
 
 
def run(n, rpm, cap, latency, spacing=0.0, retry_wait=None,
        max_attempts=3, stop_on_error=False):
    b = Bucket(rpm, cap)
    now = 0.0
    calls = r429 = done = 0
    for i in range(n):
        attempts = 0
        while True:
            attempts += 1
            calls += 1
            ok = b.take(now)
            now += latency              # time the call itself takes
            if ok:
                done += 1
                break
            r429 += 1
            if stop_on_error:           # the "error stops everything" setting
                return dict(done=done, calls=calls, r429=r429,
                            secs=round(now), stopped_at=i + 1)
            if retry_wait is None or attempts >= max_attempts:
                break                   # no retry or out of attempts: row stays empty
            now += retry_wait
        now += spacing                  # Sleep before the next row
    return dict(done=done, calls=calls, r429=r429, secs=round(now))
 
 
N, RPM, CAP, LAT = 40, 10, 10, 1.5
print("A no spacing, stop on first 429", run(N, RPM, CAP, LAT, stop_on_error=True))
print("B no spacing, retry after 60 s", run(N, RPM, CAP, LAT, retry_wait=60))
print("C no spacing, ignore failures", run(N, RPM, CAP, LAT))
print("D Sleep 6.0 s per row", run(N, RPM, CAP, LAT, spacing=6.0))
print("E Sleep 4.5 s per row", run(N, RPM, CAP, LAT, spacing=4.5))

Here is what came out.

SetupRows done429sTotal timeTakeaway
A: no spacing, stop on error13 / 40121 sStops at row 14 — the exact symptom
B: no spacing, retry after 60 s40 / 403244 sEverything lands, with three 60-second waits
C: no spacing, ignore failures19 / 402160 sThe run stays green while 21 rows end up blank
D: Sleep 6.0 s per row40 / 400300 sNo 429s, but a little over-cautious
E: Sleep 4.5 s per row40 / 400240 sNo 429s, and 60 seconds faster than D

C surprised me most. It finishes fastest and shows no error, yet 21 rows are empty, and you find out the next morning when you open the sheet. Something that stops is annoying; something that doesn't stop but quietly loses rows is far worse.

Sleep = 60 ÷ limit − the call's own duration

The gap between D and E is the main thing I wanted to show. With 10 requests a minute you need one call every 6 seconds. But those 6 seconds include the 1.5 seconds the call itself takes. Set Sleep to 6 and the real gap becomes 7.5.

Sleep seconds = 60 ÷ requests-per-minute limit − duration of one call
Example: 60 ÷ 10 − 1.5 = 4.5 seconds

You can read the call duration off Make's execution history by looking at the Claude module across a handful of runs. It grows with long outputs, so measuring beats guessing here.

I also like to add roughly ten percent of slack. If another scenario shares the same key, the bucket won't refill the way your arithmetic says. As an indie developer handling store text in several languages, I often have more than one job on the same API key, and exact calculations almost never hold.

Three places to touch in Make

Here is where each fix goes. Screen labels change with updates, so treat the names as a guide. The numbers in this article come from the mock above; I did not run an actual Make scenario for it.

GoalWhereHow to think about it
Space out the rowsA Sleep module inside the loop, next to the Claude moduleUse the formula's result. Sleep has a maximum, so split the batch if you need longer
Wait only on a 429Error handling on the Claude module: BreakSet the number of attempts and the interval; it can be shorter than 60 seconds
Don't drop failed rowsChoose Break, not IgnoreKeep incomplete executions stored so you can re-run them

Ignore gives you scenario C. Break leaves the failed rows as incomplete executions, so you don't hunt for blank cells the next morning. After one stomach-sinking morning of exactly that, Break became my rule.

Decide the wait by division, and never ignore a failure — keep it. I hold to that line however many rows I add.

If it stops anyway, check in this order

  1. In the execution history, note which row stopped and which error code came back (429, or something else).
  2. If it's a 429, open the Console limits page and see whether requests per minute or tokens per minute is closer to the ceiling.
  3. If it's requests, adjust Sleep. If it's tokens, shorten what you send per call.

If you want to go deeper into reading retry-after in code, When Your Claude API Retry Logic Made Rate Limits Worse — The Retry-After Header You Forgot to Read covers it from the developer's side. For measuring headroom from headers in production, see When Claude API Suddenly Starts Returning 429 in Production.

To start, put one Sleep of four or five seconds next to the Claude module in your own scenario. That's where I started too.

Share

Thank You for Reading

Claude 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

⬡ API & SDK2026-10-14
A 429 With retry-after: 120 Makes the Anthropic SDK Try to Wait 120 Seconds
I ran the Anthropic SDK's automatic retries against a mock server in 12 scenarios. Two retries by default, retry-after obeyed with no cap, and spend-limit 429s that no amount of waiting fixes. Code for a retry wrapper with a wait cap and a time budget, plus the logs.
⬡ API & SDK2026-10-13
Haiku 5.5 is cheaper per token, but your bill jumps fivefold past about 77k Haiku 4.5 tokens
On the price sheet, Haiku 5.5 costs roughly a tenth of Haiku 4.5. But the same text becomes about 30% more tokens, and a prompt over 100k tokens is billed at five times the rate. Here is the boundary in Haiku 4.5 terms, a script I actually ran, and the changes that return a 400.
⬡ API & SDK2026-10-08
Before Sonnet 4.5 retires, one script to find the arguments that will return a 400
claude-sonnet-4-5 retires on November 30. Swapping the model ID is not enough: budget_tokens, prefill, and tool_choice will fail. Here is a scanner built from the official migration guide, its real output, and the order I would fix things in.