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

splatEric's avatar

Surfacing json parsing errors in form request

I'm trying to use a FormRequest to validate a JSON request. Validating actual input keys etc does not seem to be a problem. However if the JSON body that has been POSTed to the endpoint is not valid JSON, the entire set of data is treated as null, instead of throwing a meaningful error that invalid data has been POSTed.

I had hoped to simply be able to do the following. However the call chain that initialises the request seems to mean that json_last_error has been reset by the time this method is called.

public function all($keys = null)
{
   $data = parent::json()->all();
   if (json_last_error() !== JSON_ERROR_NONE) {
       abort(422, 'Request body unparseable');
   }
   if ($keys === null) {
       return $data;
   }
   return collect($data)->only($keys)->all();
}

Has anyone established if there's a more reasonable way of hooking into the json parsing of the request body so that an appropriate error can be returned in the response?

0 likes
6 replies
LaryAI's avatar
Level 58

Certainly! Laravel automatically parses the JSON body of requests when the Content-Type is application/json. If that JSON is invalid, Laravel sets the request data to an empty array (i.e., null as you've discovered), but does not surface a validation or parse error by default.

To automatically return a useful error when invalid JSON is POSTed, you can create a middleware that runs before your FormRequest. This middleware validates the raw input, and aborts with a relevant error if parsing fails.

Here's how you can do it:


1. Create a Middleware

Generate a middleware called EnsureValidJson.

php artisan make:middleware EnsureValidJson

Edit the generated middleware (app/Http/Middleware/EnsureValidJson.php) as follows:

<?php

namespace App\Http\Middleware;

use Closure;

class EnsureValidJson
{
    public function handle($request, Closure $next)
    {
        // Only check for JSON when the Content-Type is application/json
        if (
            str_starts_with($request->header('Content-Type'), 'application/json') &&
            $request->getContent()
        ) {
            // Try to decode raw input
            json_decode($request->getContent());
            if (json_last_error() !== JSON_ERROR_NONE) {
                return response()->json([
                    'message' => 'Invalid JSON: ' . json_last_error_msg(),
                ], 422);
            }
        }

        return $next($request);
    }
}

2. Register the Middleware

Add your middleware to either the api middleware group (recommended for APIs) or assign it specifically to your routes in app/Http/Kernel.php:

protected $middlewareGroups = [
    'api' => [
        // ...existing API middleware
        \App\Http\Middleware\EnsureValidJson::class,
    ],
];

Or use it per route/controller if you only want specific endpoints to check:

Route::post('/your-endpoint', 'YourController@store')->middleware('ensure.valid.json');

(Don't forget to add an alias if using per-route; see Kernel.php's $routeMiddleware array.)


3. Result

Now, when an invalid JSON body is submitted, the middleware will intercept before your FormRequest runs, and the client will receive a nice 422 response like:

{
    "message": "Invalid JSON: Syntax error"
}

Summary:
A middleware checking the raw request content for valid JSON is the safest and most "Laravel way" to surface parse errors before your FormRequest runs. This approach works cleanly and provides developers/clients with meaningful feedback on malformed JSON.

ian_h's avatar

In the form request rules, you can specify json, which should then throw a 422 if it's invalid.

See the docs page for more info on this.

EDIT: This only works on a per-field basis, not the entire request body.. so not a solution for this particular problem. Leaving the comment however due to subsequent replies.

Glukinho's avatar

How to point json rule to a whole request content, not specific field? I don't see how to apply form request here. Custom middleware with json_validate($request->getContent()) should do the job.

ian_h's avatar

Good call mate.. clearly didn't take in the request properly (replied hastily while waiting for infection tests to complete)... obviously the json rule applies to a field, not the entire body.

splatEric's avatar

FWIW, I've wound up using the prepareForValidation hook of FormRequest to run a direct check on the content body and abort with a 422 status code if the JSON request is not valid.

protected function prepareForValidation()
    {
        try {
            json_decode($this->getContent(), null, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException $e) {
            abort(422, "Invalid JSON request content.");
        }

        $this->validateApplicationContext();
    }

Thanks for the various comments, appreciated!

Please or to participate in this conversation.