I love AI coding assistants.
They’re incredible at the 80%: scaffolding components, refactoring repetitive code, generating boilerplate, translating intent into TypeScript, and generally compressing time between “idea” and “PR”.
But building a real product isn’t the same thing as writing code quickly.
Real-world programming is the part nobody demos:
And that’s exactly where copilots start to feel… insufficient.
This post is a short incident report from ProteinLens:
I got rate-limited by my AI coding assistant while implementing rate limiting.
Yes, really.
I’m going through a set of “auth UX polish” tasks:
Nothing flashy. Everything important.
I checked the main auth pages:
SignupPage.tsx, which already had loading states ✅ResetPassword.tsx handles both “request reset” and “set new password” modes ✅So far so good. The “boring” work was mostly already done.
Also already implemented ✅
Nice.
Then I hit the one task that always matters when your app is public:
I searched the frontend for anything resembling rate-limit handling:
429rate limittoo many requestsRetry-AfterNothing.
The auth service had a generic handleResponse() that treated all non-200 responses as “some error”.
That’s not enough.
A 429 is not “something broke”. A 429 is “you’re fine, just not right now”.
That difference matters because it changes UX:
Retry-After, use itSo I updated the auth service to throw a dedicated error type on 429 (e.g. RateLimitError), then started wiring it into the SignIn UI.
Simple change. Small diff. Quick win.
I was mid-edit in SignIn.tsx, adding a specific branch:
RateLimitError, show calm copyAnd then my AI coding assistant returned:
Server Error: exceeded token usage
Error Code:rate_limited
I got rate-limited while implementing rate limiting.
It was funny for about 3 seconds.
Then it was annoying for 20 minutes.
And then it became the point of this article.
Copilot-style tools are great when:
They struggle when the work shifts from code to reality.
Your coding assistant can throttle you. Your cloud can throttle you. Your identity provider can throttle you. Your email provider can throttle you.
And none of those failures are “bugs” in your code.
They’re constraints.
Real-world programming is building with constraints.
The most time-consuming failures are rarely syntax or logic errors. They’re cross-layer, cross-system inconsistencies:
Copilots are good at writing code that looks right. They’re weaker at ensuring the system is right.
AI assistants often default to generic patterns:
But auth flows need bespoke UX for a small set of predictable errors:
If you treat all errors the same, you ship confusion.
And confusion is a conversion killer.
A copilot can propose code. It can’t be accountable for:
When the assistant disappears mid-flow, you still need a plan.
That’s the difference between “coding” and “engineering”.
Here’s what “good” rate-limit handling looks like in an auth UI:
Retry-AfterExample copy I like:
“You’re doing that a bit too fast. Please wait a moment and try again.”
If you want to be extra clean:
The surprising lesson wasn’t about rate limiting.
It was about developer flow.
When your assistant is part of your “shipping engine”, you need resilience in your process too.
What I do now:
keep diffs small and staged
Don’t hold the entire change in assistant context.
write the next exact steps in plain text
If the tool cuts out, you can still execute.
commit earlier
Treat it like pair-programming with someone who might leave the room.
design the codebase so it doesn’t need the assistant
Typed error contracts, consistent response handling, integration tests.
Ironically, the copilot 429 helped me adopt the same mindset I want in production:
assume dependencies fail.
If you’re implementing login/signup/reset, this is my baseline:
429 Too Many Requests consistently for abuse paths429 to a distinct error type (not generic)Retry-After header if present (optional but great)Bonus points:
No.
You’re not “too pro” for wanting this.
If anything, this is what makes the difference between:
Rate limiting, failure UX, and dependency constraints are not advanced topics. They’re the ground floor of reliability.
Copilots make you faster at writing code.
They don’t remove the need for engineering judgment.
And sometimes, they prove that point by rate-limiting you while you’re implementing rate limiting.
Perfect.