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

Andy.Lui's avatar

Is there any way to override invalidJson in Laravel 11

In the previous version, I was able to override invalidJson at App\Exceptions\Handler. However, in Laravel 11, this Handler has been removed. How can I achieve it using withExceptions in bootstrap/app.php?

class Handler extends ExceptionHandler
{
    // ...

    protected function invalidJson($request, ValidationException $exception)
    {
        return response()->json([
            'message' => $exception->getMessage(),
            'error'   => SystemErrorCode::FormValidateFailed->value,
            'data'    => $exception->errors()
        ], 200);
    }
}
0 likes
11 replies
Andy.Lui's avatar

Found a solution, I can rebind ExceptionHandler contract to my own Handler. But the code doesn't look very elegant.

$app = Application::configure(basePath: dirname(__DIR__))
    // ...
   ->create();

$app->singleton(
    \Illuminate\Contracts\Debug\ExceptionHandler::class,
    \App\Exceptions\Handler::class
);

$using = function (Exceptions $exceptions) {
    // ...
};

$app->afterResolving(
    \App\Exceptions\Handler::class,
    fn ($handler) => $using(new Exceptions($handler)),
);

return $app;
puklipo's avatar
puklipo
Best Answer
Level 9

Use render() or respond()

// bootstrap/app.php

use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;

    ->withExceptions(function (Exceptions $exceptions) {
        $exceptions->render(function (ValidationException $e, Request $request) {
            if ($request->expectsJson()) {
                return response()->json([
                    'message' => $e->getMessage(),
                    'error'   => SystemErrorCode::FormValidateFailed->value,
                    'data'    => $e->errors()
                ], 200);
            }

            return null;
        });
2 likes
martinbean's avatar

@andy.lui Why on earth would you return a 200 OK HTTP status code from an error? That’s a massive reason for why you shouldn’t be overriding that method.

Andy.Lui's avatar

@martinbean Because our front-end engineers felt it difficult for them to handle these error codes well. 😔

martinbean's avatar

@Andy.Lui So everything just comes back 200 OK? 🙃

It’s more difficult to introspect every AJAX response to see if it was an error or not, than it is to just check the status code. Most libraries even throw errors if the status code isn’t in the successful range, meaning you can do this:

try {
    // Response was successful
    // Parse data knowing it's good data
} catch (e) {
    // Response was not successful
    // Handle error condition accordingly
}

Now, your front-end engineers have to look at the response of every request, and duplicate error checking logic for each and every one of those requests:

if ('error' in response) {
    // Yes, now horrible logic to check what type of error
    // that will be duplicated across each and every request
    // in the front-end application
} else {
    // Handle logic as if request was successful
    // Hoping you've caught every possible error condition
    // in the if statement above
}

Your front-end engineers are lazy and should not be dictating how the back-end formats or serves API responses. You shouldn’t be completely throwing out appropriate HTTP status codes or good practices just because your front-end engineers moan it’s “difficult” to do things properly.

Strorge's avatar

While App\Exceptions\Handler is gone in Laravel 11, there's a new way to achieve custom JSON responses for validation errors. Here's how you can do it using the withExceptions method in bootstrap/app.php:

PHP use Illuminate\Validation\ValidationException;

$app->singleton(JsonExceptionHandler::class, function ($app) { return new class extends JsonExceptionHandler { public function renderForRequest(Request $request, Exception $e) { if ($e instanceof ValidationException) { return response()->json([ 'message' => $e->getMessage(), 'error' => SystemErrorCode::FormValidateFailed->value, 'data' => $exception->errors() ], 422); // Set your preferred status code here (e.g., 422 for Unprocessable Entity) }

        return parent::renderForRequest($request, $e);
    }
};

});

This code defines a custom JsonExceptionHandler class that overrides the default renderForRequest method. Inside the method, you can check if the exception is a ValidationException and then return your desired JSON response with the error message, code, and data (similar to your previous approach).

Key points:

We use a singleton to register our custom exception handler. The status code in the response can be adjusted based on your needs (e.g., 422 for validation errors).

tonymans33's avatar

I found this solution to be the cleanest one. with a little help from Claude ai XD

in bootstrap/app.php

// first import your (customized handler that you've overridden) 
use App\Exceptions\Handler;

->withExceptions(function (Exceptions $exceptions) {

        // Handle exceptions for JSON responses
        // 
        // If the request expects a JSON response, then we want to render the exception
        // in a format that is easy to parse by the client.
        // This is done by using the `Handler` class from the `app/Exceptions` folder.
        // The handler will convert the exception into a JSON response.
        $exceptions->renderable(function (\Throwable $e, $request) {
            if ($request->expectsJson()) {
                $handler = new Handler(app());
                return $handler->render($request, $e);
            }
        });
    })->create();
1 like

Please or to participate in this conversation.