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

mcbates's avatar

How to debug validation errors thrown by Form Request?

When I use Form Request and test my submissions, I often end up with Illuminate\Validation\ValidationException: The given data was invalid. without any hint which data is wrong or missing. Disabling exception handling does not improve the error message.

I tried to output the session errors in the test with dd($request->session()->all() but the exception breaks the test before that already.

How can I get the exact validation error(s) in my test?

Here's a basic setup to see what I mean:

// TestFormRequest
public function rules()
    {
        return [
        'size' => 'required', 
            'department' => 'required',
        ];
    }

// Controller
public function store(TestFormRequest $request)
    {
        Company::store($request->validated());
    }
// Test the happy path, but has an error (size ommited on purpose to test exception message)
/** @test */
public function test() {
   $this->withoutExceptionHandling();
    $response = $this->actingAs($user)->post(route('company.store'), [
            'department' => 'Admin',
            // 'size' ommited on purpose to simulate the exception error message
    ]);

$response->assertRedirect(route('home'));
}

I would expect an exception along the following lines:

Illuminate\Validation\ValidationException: The given data was invalid. Size is missing.

Instead I get no details on my validation error, just a generic exception:

# Error Output when running test
Illuminate\Validation\ValidationException: The given data was invalid.
   │
   ╵ /Users/test/Sites/test/vendor/laravel/framework/src/Illuminate/Foundation/Http/FormRequest.php:130
   ╵ /Users/test/Sites/test/vendor/laravel/framework/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php:26
   ╵ # REDACTED TO IMPROVE READABILITY
   ╵ /Users/test/Sites/test/tests/Feature/Strike
   ╵ /Users/test/Sites/test/tests/Feature/StrikeTest.php:148
0 likes
12 replies
Nakov's avatar

@mcbates this is an example of how I do it. I use assertSessionHasErrors for specific input data, for example using your data:

$this->post(route('company.store'))
            ->assertRedirect()
            ->assertSessionHasErrors([
                'department'
            ]);
mcbates's avatar

Thanks for the answer, but I don't want to assert the error. I want to test the happy path and the test fails because the form data is incorrect. I want to debug what is going wrong.

Nakov's avatar

@mcbates but as you can see from your rules you have two required fields, and you are passing just one with this code:

$response = $this->actingAs($user)->post(route('company.store'), [
            'department' => 'Admin',
    ]);

You are missing the size as far as I can see. And to get a better exception to check this use :

$this->withoutExceptionHandling();

At the beginning of your test.

mcbates's avatar

I omit the second parameter (size) on purpose to replicate the error message I get. I know that I need to add size to the post request to make it pass, but it's not about this special case but for the general debugging. Often I don't know exactly what is wrong with the form request and have to compare test and Form Request. I prefer to get an expressive error message that just tells me what is going wrong.

$this->withoutExceptionHandling() does not improve the error message. I actually had it before and added it to the minimal example.

Nakov's avatar

Okay then, I don't understand you, sorry. You said you want to test the happy path, but having error in the response is not a happy path.

And I don't think that there is another way then the assertSessionHasErrors and for testing purposes in my view it is good enough, as I don't want to have to change the test each time I customize the error message, I just want to be sure that if I enter invalid data I error in the session.

Actually even with assertSessionHasErrors you can test the exact message:

->assertSessionHasErrors(['field' => 'Field error message.']);
mcbates's avatar

| having error in the response is not a happy path.

I simulate an error in my happy path test, because I want to throw the exception and demonstrate that you cannot derive the validation error from there.

That is my question: How to see from the exception log which validation error I have. In my case it should say something like the following:

Illuminate\Validation\ValidationException: The given data was invalid. Size is missing.

It does not tell me anything about the specific error though and I have to deep dive in the Form Request itself and compare it with my test.

Nakov's avatar

Well you will not get that data using the FormRequest as those errors are shared in the session, and the form request if the validation fails it just throws the ValidationException which in turn has this in the constructor:

parent::__construct('The given data was invalid.');

So you should use the Validator in the controller if you want to achieve that. And make the response yourself, putting the errors in the response instead of the session.

mcbates's avatar

I don't get why ValidationException does not pass the errors in the constructor as well. This would make the error message a lot more helpful.

Nakov's avatar

@mcbates actually you need this in your method:

$this->withExceptionHandling();

This will show you the correct errors, without handling them in the test.

mcbates's avatar
mcbates
OP
Best Answer
Level 4

This is how you get helpful error messages when using a form request:

  1. Make sure exception handling is enabled (no $this->withoutExceptionHandling(); present, $this->withExceptionHandling(); is not needed, as it's the default)
  2. Add this as your first assertion: $response->assertSessionHasNoErrors();
  3. When this assertion fails, it will show you the exact session error

Example:

  • field count has validation rule ['required', 'integer']
  • you pass ['count' => 'string'] in your test's post request
  • This is the error message you get
Session has unexpected errors:               
   ├                                              
   ├ [                                            
   ├     "count must be integer."
   ├ ]                                            
   ├ Failed asserting that true is false.
4 likes
mcbates's avatar

@nakov Thanks for helping me find the right answer, I really appreciate it!

Nakov's avatar

@mcbates happy that it helped somehow. Thanks for posting the solution, it will be helpful to someone else I believe.

Please or to participate in this conversation.