Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

BorisTheTripper's avatar

Handle 429 (too many requests) in Inertia.js

How do I handle a 429 error (or any error in fact), when working with Inertia forms? I tried the callback onError, but it didn't work:

post(route("verification.send"), {
  onSuccess: () => {
    console.log("verification email sent");
  },
  onError(error) {
    console.log("couldn't resend verification email");
    console.log(error);
  },
});

What happens instead is a repaint, with Laravel's standard 429 | Too many requests error screen. I figured this is because I need a JSON response, so I tried creating a middleware, but to no avail:

class EnsureJsonResponse
{
    public function handle(Request $request, Closure $next)
    {
        $request->headers->set('Accept', 'application/json');
        $request->headers->set('Content-Type', 'application/json');

        return $next($request);
    }
}

then in bootstrap/app.php:

$middleware->appendToGroup('json.response', [
    \App\Http\Middleware\EnsureJsonResponse::class,
]);

then on route:

Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
            ->middleware(['json.response', 'throttle:1,0.5'])
            ->name('verification.send');

Anyone know what the actual problem is?

0 likes
5 replies
richardhulbert's avatar

@boristhetripper You haven't pasted the the full code so I am checking that you have first done this:

import { router } from '@inertiajs/vue3

and then this should work:

router.post("verification/send", {
data,
  onSuccess: () => {
    console.log("verification email sent");
  },
  onError(error) {
    console.log("couldn't resend verification email");
    console.log(error);
  },
});

In dev tools in your browser check that the request looked correct and that the correct values were passed.

BorisTheTripper's avatar

@richardhulbert yes, my JS code is fine. From what I understand, the onError callback is only invoked when there's a validation error, i.e. it doesn't apply to middleware exceptions like 429? This would explain why the error can't be handled in this way.

I'm trying to understand if it's even possible to handle an error in Inertia by passing it as a prop. I've even tried adding the following logic to bootstrap/app.php, but that just throws 500:

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->respond(function (Response $response, Throwable $exception, Request $request) {
        if ($response->getStatusCode() === 429) {
                return back()->with([
                    'message' => 'The page expired, please try again.',
                ]);
          }

		return $response;
    });
richardhulbert's avatar

@BorisTheTripper I tend to use axios for things like forms even when using Inertia (only through laziness and familiarity) but you seem to be having a problem at the server rather than in the client (Inertia).

So when you visit the route verification/send, as a post, you get the 429 error - too many requests in a given time. Have you checked to see if there is some sort of a route clash - perhaps run

php artisan route:list

I think at this point I would create a simple feature test that tested that endpoint is basically working.

BorisTheTripper's avatar

@richardhulbert No-no, the 429 is intentional and happens as expected. My question was whether it's possible to gracefully handle this exception in an "Inertia" way, i.e. without resorting to things like axios.

The only solution I've been able to come up with (outside of using axios) is to define a custom error handler as per the docs, except that mine will also look for a custom header in the request and conditionally return back()->withErrors(), passing JSONified response data as a prop to Inertia.

A very hacky solution, AFAIU. But, from the little testing I've done so far, seems to work.

kylemilloy's avatar

To anyone discovering this later, the above code works but needs updates:

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->respond(function (Response $response, Throwable $exception, Request $request) {
        if ($response->getStatusCode() === 429) {
                return back()->with([
                    'message' => 'The page expired, please try again.',
                ]);
          }

		return $response;
    });

The problem here is that the response can be a lot of different kinds of responses, it can be json responses, inertia responses, laravel responses, etc.

Remove the Response $response type hint and change the check to see the instance of the exception thrown to handle your specific case. In mine, I want to gracefully handle throttling so use the TooManyRequests exception

use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->respond(function ($response, Throwable $exception, Request $request) {
        if ($exception instanceof TooManyRequestsHttpException) {
                return back()->with([
                    'message' => 'Slow tf down!',
                ]);
          }

		return $response;
    });

Please or to participate in this conversation.