statamic / cms

The core Laravel CMS Composer package
https://statamic.com
Other
4.08k stars 533 forks source link

Serialization of 'Closure' is not allowed #8406

Closed geertjanknapen1 closed 1 year ago

geertjanknapen1 commented 1 year ago

Bug description

When trying to activate an account, if the password and password confirmation do NOT match, I get the following exception. If the passwords do match, everything is fine. Not sure but this could just not be Statamic related but a Laravel thing

image

How to reproduce

Logs

[2023-07-05 11:30:30] local.ERROR: Serialization of 'Closure' is not allowed {"userId":14,"exception":"[object] (Exception(code: 0): Serialization of 'Closure' is not allowed at /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Session/Store.php:173)
[stacktrace]
#0 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Session/Store.php(173): serialize(Array)
#1 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(238): Illuminate\\Session\\Store->save()
#2 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(130): Illuminate\\Session\\Middleware\\StartSession->saveSession(Object(Illuminate\\Http\\Request))
#3 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest(Object(Illuminate\\Http\\Request), Object(Illuminate\\Session\\Store), Object(Closure))
#4 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#5 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#6 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#7 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#8 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#9 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#10 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(798): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#11 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(777): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))
#12 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(741): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))
#13 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(730): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))
#14 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(200): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))
#15 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))
#16 /usr/share/nginx/html/vendor/statamic/cms/src/Http/Middleware/DisableFloc.php(18): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#17 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Statamic\\Http\\Middleware\\DisableFloc->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#18 /usr/share/nginx/html/vendor/statamic/cms/src/Http/Middleware/CheckMultisite.php(14): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#19 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Statamic\\Http\\Middleware\\CheckMultisite->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#20 /usr/share/nginx/html/vendor/statamic/cms/src/Http/Middleware/CheckComposerJsonScripts.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#21 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Statamic\\Http\\Middleware\\CheckComposerJsonScripts->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#22 /usr/share/nginx/html/vendor/statamic/cms/src/Http/Middleware/PoweredByHeader.php(19): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#23 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Statamic\\Http\\Middleware\\PoweredByHeader->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#24 /usr/share/nginx/html/vendor/barryvdh/laravel-debugbar/src/Middleware/InjectDebugbar.php(66): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#25 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Barryvdh\\Debugbar\\Middleware\\InjectDebugbar->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#26 /usr/share/nginx/html/vendor/withcandour/aardvark-seo/src/Http/Middleware/RedirectsMiddleware.php(16): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#27 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): WithCandour\\AardvarkSeo\\Http\\Middleware\\RedirectsMiddleware->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#28 /usr/share/nginx/html/app/Http/Middleware/SetGlobalDefaults.php(29): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#29 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\SetGlobalDefaults->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#30 /usr/share/nginx/html/app/Http/Middleware/SetDefaultLocaleForUrls.php(41): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#31 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\SetDefaultLocaleForUrls->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#32 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#33 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#34 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#35 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#36 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#37 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#38 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#39 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#40 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#41 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#42 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#43 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Http\\Middleware\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#44 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#45 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Http\\Middleware\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#46 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#47 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(175): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#48 /usr/share/nginx/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(144): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))
#49 /usr/share/nginx/html/public/index.php(51): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))
#50 {main}
"}

Environment

Environment
Application Name: [REDACTED]
Laravel Version: 10.13.5
PHP Version: 8.2.6
Composer Version: 2.5.7
Environment: local
Debug Mode: ENABLED
URL: [REDACTED].test
Maintenance Mode: OFF

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: redis
Database: mysql
Logs: stack / daily
Queue: database
Session: file

Statamic
Addons: 4
Antlers: runtime
Stache Watcher: Disabled
Static Caching: Disabled
Version: 4.6.0 PRO

Statamic Addons
aryehraber/statamic-impersonator: 2.5.0
spatie/statamic-responsive-images: 4.0.3
statamic/eloquent-driver: 2.0.0
withcandour/aardvark-seo: 3.0.0

Installation

Fresh statamic/statamic site via CLI

Antlers Parser

regex (default)

Additional details

I have extended the Validation, registered Blade directives and registered view composers. If I understand correctly those are Closures, and I also saw they are present in the session (unsure if they should be).

geertjanknapen1 commented 1 year ago

Update, it happens whenever there is an exception on the Activate account page. Not only regarding the passwords, but also password too short for example.

jasonvarga commented 1 year ago

I have extended the Validation, registered Blade directives and registered view composers.

Could you provide these?

geertjanknapen1 commented 1 year ago

@jasonvarga

Below you can find all of them. They are all in AppServiceProvider::boot() and it seems it's tried to save them in session (which throws the error), but since I am not saving them to session I don't know where or why that is happening.


Validation extends;

// Register custom site validation rules (e.g. for adding validation rules to form fields)
Validator::extend(
    'phone',
    function ($attribute, $value, $parameters, $validator) {
        return (new Phone())->passes($attribute, $value);
    }
);

// Register custom statamic control panel validation rules
Validator::extend(
    'must_have_specific_term',
    function ($attribute, $value, $parameters, $validator) {
        return (new MustHaveSpecificTerm())->passes($attribute, $value);
    }
);

Check if input matches a phone number

class Phone implements Rule
{
    public function passes($attribute, $value)
    {
        return Regex::match('/^[0-9\-\(\)\x20\+]*$/', $value)->hasMatch();
    }

    public function message()
    {
        return '';
    }
}

Check if an Entry has a taxonomy term (we call them tags) of a specific type

class MustHaveSpecificTerm implements Rule
{
    public function passes($attribute, $value)
    {
        // 'tags' is a Terms field
        if ($attribute === 'tags') {
            $tagHandle= Taxonomy::CATEGORY->value . '::';

            foreach ($value as $tag) {
                if (str_contains($tag, $tagHandle)) {
                    return true;
                }
            }
        }

        return false;
    }

    public function message()
    {
        return '';
    }
}

Blade directives;

Calls getTranslation method on the Entry ($page) in order to get translations from a Statamic array or globals Other one checks if a key in session is equal to a value

/** Blade directive to get translation key from globals */
Blade::directive('translate', function (string $translationKey) {
    return '<?= !empty($page) ? $page->getTranslation(' . $translationKey . ') : translate(' . $translationKey .') ?>';
});

 Blade::if('sessionValueIs', function ($key, $value) {
    return (session()->get($key) && session()->get($key) === $value);
});

Viewcomposers;

Passes supported languages, locale, contentType (either commercial or not commercial) and isCommercial boolean to all views

View::composer('*', function (IlluminateView $view) {
    /** Pass Statamic global sets to every view */
    GlobalSet::all()->each(fn($set) => $view->with($set->handle(), $set->inCurrentSite()));

    /** Pass selected variables to every view */
    $view
        ->with('supportedLanguages', app(ITranslationService::class)->getAcceptedLocales())
        ->with('locale', app()->getLocale())
        ->with('contentType', request()->get('contentType'))
        ->with('isCommercial', request()->get('isCommercial'));
});
edalzell commented 1 year ago

Is it possible Statamic isn't booted yet? What if you put all of those that reference Statamic in a Statamic::booted()?

jasonvarga commented 1 year ago

The only suspicious part about any of that to me is this one, because it's accessing the session.

Blade::if('sessionValueIs', function ($key, $value) {
    return (session()->get($key) && session()->get($key) === $value);
});

Can you try commenting that one out and trying to trigger the validation error again?

Everything else doesn't seem to me like it would be a problem. I don't see why any of those would go into the session.

geertjanknapen1 commented 1 year ago

Commenting that out, clearing cache and restarting the docker containers does not change anything. It still throws the same error.

geertjanknapen1 commented 1 year ago

Is it possible Statamic isn't booted yet? What if you put all of those that reference Statamic in a Statamic::booted()?

Hey @edalzell , didn't notice your comment, and also failed to clarify. But to my knowledge nothing is referencing Statamic. Yes the rules are referencing the data column of an entry but the rule works, it's just that it seems to try to save it in session which is breaking.

Issue got put on the backburner (since we use Azure to authenticate new users we can handle creating accounts ourselves, it'd just be nicer to have it working). But I'm starting to suspect it might be Laravel-related and not Statamic.

jackmcdade commented 1 year ago

Yeah we can't recreate this here at all – if you're able to do so on a new, empty Statamic site, we can use that to dig in, otherwise i think we need to look at something in Laravel-land as the culprite.