laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.52k stars 11.02k forks source link

Validation messages not always showing #27729

Closed DanielMalmgren closed 5 years ago

DanielMalmgren commented 5 years ago

Description:

I've got some kind of strange race condition here... I have got a form posting to Laravel. The function receiving the post currently looks like this:

    public function store(Request $request, Workplace $workplace) {
        usleep(50000);
        $request->validate(
            [
                'starttime' => 'required',
                'endtime' => 'required|after:starttime',
                'date' => 'required',
                'workplace_id' => 'required'
            ],
            [
            'starttime.required' => __('Du måste ange en starttid!'),
            'endtime.required' => __('Du måste ange en sluttid!'),
            'date.required' => __('Du måste ange ett datum!'),
            'endtime.after' => __('Sluttiden får inte inträffa före starttiden!')
        ]);

        //Removed code to save stuff to db, not relevant here

        return redirect('/')->with('success', 'Projekttiden har registrerats');
    }

The strange thing here is that if I remove the first line (the delay), my error messages only pops up in the browser sometimes, like one time in two (seemingly randomly distributed). Discovered this first by adding a debug log output, which obviously took enough time for things to work... The validation always works (ie the code after the validate() call don't get executed) but the user gets no notification about what's wrong.

Anyone seen this before?

This happened also in Laravel 5.7, just never got around to report it. Now on 5.8. Happens both on my dev machine (hyperv Homestead) and production machine (Ubuntu 18.04).

I don't know if it's relevant, but here's my code for displaying the errors:

@if($errors->any())
    @foreach($errors->all() as $error)
        <div class="alert alert-danger">
            {{$error}}
        </div>
    @endforeach
@endif

@if(session('success'))
    <div class="alert alert-success">
        {{session('success')}}
    </div>
@endif

@if(session('error'))
    <div class="alert alert-danger">
        {{session('error')}}
    </div>
@endif
ManojKiranA commented 5 years ago

what is your is issue You are facing

Are You getting the

Validation failure but no error message OR

Validation success and data is being processed

staudenmeir commented 5 years ago

Can you reproduce this on a fresh installation of Laravel?

DanielMalmgren commented 5 years ago

ManojKiranA: I really don't understand your question... The validation succeeds, but sometimes the error messages doesn't contain anything.

staudenmeir: Good question. Haven't tried that. Guess it could be worth testing.

Btw, I have now also tried simply dd:ing $errors and when the error messages don't display, the errorbag is definitely empty.

Also, forgot to mention in the original report, I've tried with a custom FormRequest as well, gives the exact same behaviour.

ManojKiranA commented 5 years ago

try this create file named as flash-message.blade.php in projectname/resource/views/

and paste the following code into it

@if ($message = Session::get('success'))
<div class="alert alert-success alert-block">
    <button type="button" class="close" data-dismiss="alert">×</button> 
        <strong>{{ $message }}</strong>
</div>
@endif

@if ($message = Session::get('error'))
<div class="alert alert-danger alert-block">
    <button type="button" class="close" data-dismiss="alert">×</button> 
        <strong>{{ $message }}</strong>
</div>
@endif

@if ($message = Session::get('warning'))
<div class="alert alert-warning alert-block">
    <button type="button" class="close" data-dismiss="alert">×</button> 
    <strong>{{ $message }}</strong>
</div>
@endif

@if ($message = Session::get('info'))
<div class="alert alert-info alert-block">
    <button type="button" class="close" data-dismiss="alert">×</button> 
    <strong>{{ $message }}</strong>
</div>
@endif

@if ($errors->any())

<div class="alert alert-danger">
    <button type="button" class="close" data-dismiss="alert">x</button> 
    Please check the form below for errors
</div>
@endif

@if ($errors->any())

<div class="alert alert-danger">
    <button type="button" class="close" data-dismiss="alert">x</button> 
    {{ implode('', $errors->all(':message')) }}
</div>

@endif

Now Open Your projectname/resource/views/layouts/app.blade.php

and incude that @include('flash-message')

and you will get something please comment the result

ManojKiranA commented 5 years ago

Can you reproduce this on a fresh installation of Laravel?

its not the solution think a situation if he has done many modules in project

DanielMalmgren commented 5 years ago

Ok, added that code. When the displaying of my own errors don't work that one doesn't either, but when my errors display I get the following:

Please check the form below for errors Du måste ange en starttid!Du måste ange en sluttid!Du måste ange ett datum!

I think this leads to the same conclusion as all other tests I've done: Sometimes there are no errors produced even though the validation fails. Since a short delay in the store function makes things work it must have something to do with the $errors array not being populated fast enough. Don't know enough about the inner workings to understand exactly what's happening though...

ManojKiranA commented 5 years ago

Have You tried FormRequest

DanielMalmgren commented 5 years ago

Yep. Mentioned that above. Makes no difference.

ManojKiranA commented 5 years ago

try the Validator Facade Method

public function store(Request $request, Workplace $workplace) {
    {       
        $input = $request->all();
        $validator = \Validator::make(
            $request->all(), 
                [
                    'starttime' => 'required',
                    'endtime' => 'required|after:starttime',
                    'date' => 'required',
                    'workplace_id' => 'required'
                ],

                [
                    'starttime.required' => __('Du måste ange en starttid!'),
                    'endtime.required' => __('Du måste ange en sluttid!'),
                    'date.required' => __('Du måste ange ett datum!'),
                    'endtime.after' => __('Sluttiden får inte inträffa före starttiden!')
                ]

        );

        if ($validator->fails()) {
                  return redirect()->back()
                                  ->withErrors($validator)
                                  ->withInput($input);
        }
     return redirect('/')->with('success', 'Projekttiden har registrerats');
    }
DanielMalmgren commented 5 years ago

Nope, that gives the same problem :-(

rs-sliske commented 5 years ago

do you have your app open in another tab that could be affecting your session?

devcircus commented 5 years ago

May not be the case here, but the answer usually resides in the code deemed "irrelevant".

DanielMalmgren commented 5 years ago

rs-sliske: Nope, only one tab open.

devcircus: The code I deemed as irrelevant is never reached at all, since the validation fails. Verified that by a logger() call as the first row after the validation.

driesvints commented 5 years ago

@DanielMalmgren can you create an app with a minimum setup that re-creates the problem which we can test with?

guccilive commented 5 years ago

I'm facing the same issue. I even created two different fresh projects on 5.8 version but still facing the same problem with Validation customized message/rule or custom Request Class. No error, Not executing method after submit. For example, this basic code:

`use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Http\Controllers\Controller;
use App\ModelAuth\Role;
use App\Http\Requests\AddUserRoleRequest;
use Carbon\Carbon;
use Session;

class UserRoleController extends Controller
{
    public function ShowRoleForm()
    {
        $roles = Role::all();
        return view('admin.setting.user-role', compact('roles'));
    }
public function AddUserNewRole( Request $req)
{
    $custom_message = [
        'name.required' => 'Le champ Nom est requis.',
        'name.unique' => 'Ce nom existe déjà.',
        'description.required' => 'Le champ Description est requis',
      ];
      $this->validate($req,[
        'name' => 'required|unique:roles',
        'description' => 'required',
      ], $custom_message);

    $roles = new Role;
    $roles->name = $req->name;
    $roles->description = $req->description;
    $roles->save();

    Session::flash('successMsg','Role ajouté avec succè!');
    return redirect()->back();
}

}`

Model: `<?php

namespace App\ModelAuth;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;

class Role extends Model
{
    use Notifiable;
protected $fillable = ['name','description'];

protected $primaryKey ='id';

protected $table ='roles' ;

} `

driesvints commented 5 years ago

@DanielMalmgren @guccilive are you both still experiencing this?

DanielMalmgren commented 5 years ago

Yep, the problem persists in 5.8.8. Haven't got any time for digging any deeper though, for now I'm just putting usleep() calls in the beginning of all my store functions.

laurencei commented 5 years ago

@DanielMalmgren - what session driver are you using?

Can you try switching to a different session driver and trying again?

DanielMalmgren commented 5 years ago

@laurencei Sorry, forgot to mention here. I'm normally using file session drivers, but I've already tried changing to database, didn't make any differene.

laurencei commented 5 years ago

Is the form behind an auth page - i.e. do you need to be logged in to see it? The most common reason for failed validation messages is a session failure.

my dev machine (hyperv Homestead)

Homestead has Redis - try switching to a Redis session driver and see if it happens there? Both file + database are not true atomic storage.

laurencei commented 5 years ago

Also @staudenmeir asked this a while ago:

Can you reproduce this on a fresh installation of Laravel?

to which you replied

Good question. Haven't tried that. Guess it could be worth testing.

The default Laravel install with default auth gives you a good starting point. Create a basic form and see if you can reproduce there. If not, slowly add stuff back in until the problem arises...

DanielMalmgren commented 5 years ago

Is the form behind an auth page - i.e. do you need to be logged in to see it? The most common reason for failed validation messages is a session failure.

The entire site is behind SAML2 authentication (https://github.com/aacotroneo/laravel-saml2). I tried disabling authentication now though, going completely unauthenticated, and the problem persists.

my dev machine (hyperv Homestead)

Homestead has Redis - try switching to a Redis session driver and see if it happens there? Both file + database are not true atomic storage.

Ok, tried redis too. Same problem.

The default Laravel install with default auth gives you a good starting point. Create a basic form and see if you can reproduce there. If not, slowly add stuff back in until the problem arises...

Yep, I guess this is the next time to test. Too tight schedule currently though, guess this will need to hang in the air until I get time to test.

laurencei commented 5 years ago

Essentially it has to boil down to one of two things:

  1. If you can create this on a basic install of Laravel with no other code changes, then it is somehow related to your environment, infrastructure etc.

  2. If you cannot re-create this on a basic Laravel; then something in your code is interfering with the internal code and causing the bug.

Either way, it's fairly safe to say this is not Laravel specific at this point in time. It's not reproducible for anyone else with the scenario you've given. The only thing I can think of is some strange environment setup that causes an edge case, in which situation that might be a Laravel bug. But until you can point it down one way or the other, there's not much we can do here.

Once you track it down, ping us and we can reopen this with new information.

Adam-78 commented 5 years ago

I've just upgraded to laravel 5.8 from 5.7 and I've noticed the same issue. Validation works i.e user is redirected to the form page but no validation messages are showing.

jereconjota commented 5 years ago

any solutions? i have same issue v5.8.28

DanielMalmgren commented 5 years ago

I never found any solution. There's obviously a bug here somewhere but I haven't succeeded in proving exactly where, so for the time being I'm living with usleep() calls the first thing in all my store, update and destroy methods. I don't know though if any devs are still reading here now that the ticket is closed?

devcircus commented 5 years ago

Like was mentioned already, the best way to track it down to a bug in your code or a hug in the framework is to create a new laravel app and only add the relevant code for showing the error messages. If the bug persists in a new app, push that app to github so the community can help.

aline-matos commented 5 years ago

Same issue, v5.8.28, with redis:

return redirect()->route('login')->with('error', 'The credentials do not match our records');
Array (
    [_token] => osjrWEce4fVzbg4XJtqvr1JeTBfhViputIqkv7qd
    [_previous] => Array (
            [url] => http://127.0.0.1:8001/login
        )
    [_flash] => Array (
            [old] => Array ( )
            [new] => Array ( )
        )
)
jereconjota commented 5 years ago

I never found any solution. you had lucky?

jereconjota commented 5 years ago

I solved this problem by changing xampp to mamp

binaryhq commented 4 years ago

This might help.

https://stackoverflow.com/a/59420073/3738033

oza75 commented 4 years ago

Moving \Illuminate\Session\Middleware\StartSession::class and \Illuminate\View\Middleware\ShareErrorsFromSession::class from web $middlewareGroups to $middleware in app\Http\Kernel.php solve this issue !

But I don't know if this can cause unexpected behavior on Api routes

utkubasaran commented 4 years ago

use Illuminate\Support\Facades\Validator; use Illuminate\Http\Request;

public function store(Request $request) {

        $input = $request->all();

        $validator = Validator::make(
            $request->all(),
            [
                'name' => 'required|max:255',
            ],
            [
                'name.required' => 'your message here'
            ]
        );

        if ($validator->fails()) {
            return redirect('/')
                ->withInput($input)
                ->withErrors($validator);
        }
    }
almirhodzic commented 2 years ago

I having the exact same problem here! Laravel 9.28 on xampp 8.1.6 -> Win10. Did anyone found a solution?

almirhodzic commented 2 years ago

I having the exact same problem here! Laravel 9.28 on xampp 8.1.6 -> Win10. Did anyone found a solution?

Found the bug, in livewire.php configfile, the Assets and App_url was wrong pointed.

tiagoskaterock commented 1 year ago

I've started a new Laravel project about 1 month ago and I am facing this problem too.

Sometimes Laravel Validation works fine, but in others they simply go back to the form and does not show the errors.

I test the same error many times, and it look like it only works properly whenever it wants.

It's like it works fine and show the errors 2 or 3 times and then on the next test it shows just a list with no errors, even the validation working nice.

I am reading a lot of forums about that but in no place I found the answer.

The flash message are also the same way, sometime it works and sometimes don't.

I don't know if it is my computer, or OS, or browser, Laravel version, extensions, or whatever...

Using Chrome and Ubuntu 18.04

FabianoLothor commented 1 year ago

Jeez...

This one was pretty hard to figure out.

There are a lot of similar related issues what turns that very tricky.

I think here is the right thread to share what I found.


For instance, I'm working in a legacy system that was updated from Laravel 5.2 to 5.5 a few months ago, so keep in mind that your issue might be different.

Initially I thought that it could be due the settings of the middlewares, more about that in the links below:


After a few hours without success or anything really helpful, I decided to dig the old code with Laravel 5.2.

Well, they changed the behavior of ValidatesRequests trait. Not only, but mainly the function validate:

// 5.5
    public function validate(Request $request, array $rules,
                             array $messages = [], array $customAttributes = [])
    {
        $this->getValidationFactory()
             ->make($request->all(), $rules, $messages, $customAttributes)
             ->validate();

        return $this->extractInputFromRules($request, $rules);
    }
// 5.2 - I didn't look carefully, but it seems that wasn't changed until 5.4
    public function validate(Request $request, array $rules, array $messages = [], array $customAttributes = [])
    {
        $validator = $this->getValidationFactory()->make($request->all(), $rules, $messages, $customAttributes);

        if ($validator->fails()) {
            $this->throwValidationException($request, $validator);
        }
    }

After figured out that, I went back to the docs and didn't find anything related to that.

image

Anyway, it seems that after 5.5 if you want to send the errors and the inputs to the view, instead of only do return back();, you will need to use something like return back()->withInput()->withErrors($exception->validator ?? '');.

Alternatively,you can create a custom trait using the old code from 5.2 (perhaps combine both) and override the uses of ValidatesRequests to CustomValidatesRequests.

After recover the trait from 5.2, the error messages came back to the system. :smiley:

Despite of that, keep in mind this might cause other issues, if possible it's better to use ->withInput()->withErrors($exception->validator ?? '');.

erlangparasu commented 4 months ago

Any updates? Got this issue on Laravel 7.x

Session::flash always give empty data, internally laravel use flash with key 'errors', that cause bind to view $errors be empty too.

tags: session, flash, errors, redirect, withErrors, validation, messages