laravel/serializable-closure

Serializable closure breaks the Symfony var-dumper

borys-p opened this issue · 5 comments

Serializable Closure Version

1.3.1

PHP Version

8.2.8

Description

This issue is again related to an Exception, but in a more typical way: when you try to dump() an Exception with laravel-serializable-closure in the stack trace, it will break inside the Symfony var-dumper:

Unexpected ErrorException thrown from a caster: is_file(): Unable to find the wrapper "laravel-serializable-closure" - did you forget to enable it when you configured PHP?

It's happening in the following part of Symfony\Component\VarDumper\Caster\ExceptionCaster, which attempts to analyze the stack trace:

                if (is_file($f['file']) && 0 <= self::$srcContext) {
                    if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) {

This seems to be an actual bug, as dump() is a standard tool in Laravel.

Steps To Reproduce

As above, just dump() an Exception that's originated in the Serializable Closure.

Heya, thanks for reporting.

We'll need more info and/or code to debug this further. Can you please create a repository with the command below, commit the code that reproduces the issue as one separate commit on the main/master branch and share the repository here? Please make sure that you have the latest version of the Laravel installer in order to run this command. Please also make sure you have both Git & the GitHub CLI tool properly set up.

laravel new bug-report --github="--public"

Please do not amend and create a separate commit with your custom changes. After you've posted the repository, we'll try to reproduce the issue.

Thanks!

Okay, this seems more complicated than I thought, as I can't reproduce it with a simple example. There's obviously something more to it, I'll keep narrowing it down. It's not the first time I ran into this issue, so it's reproductible, I just need to find the root cause.

I think I see what's going on and why I wasn't able to reproduce it before. This behavior is triggered by a specific code path, and only when working with task workers in Octane (or multiple PHP processes in general):

  1. SerializableClosure is created in the main worker. This calls Native::__serialize().
  2. The closure is passed to a task worker, where it is automatically unserialized. This calls Native::__unserialize(), which also registers the stream wrapper. All is fine so far.
  3. Task worker throws an exception. I pass it back to the main worker without stack trace arguments (actually, they're stringified, but that doesn't matter). Some of the file properties of the stack trace start with the laravel-serializable-closure:// stream definition.
  4. Remember that the stream wrapper was registered in the task worker, but not the main worker? Now calling dump() in the main worker will fail.

tl;dr: calling dump() on a stack trace returned from another process will make the code go boom.

My workaround was to add ClosureStream::register(); to the AppServiceProvider, so the stream wrapper is always registered in every running PHP process. But you will probably have a better idea how to handle it.

@borys-p Can you detail all the commands / steps, I need to type locally so I can reproduce that issue?

Closing this issue because it's inactive, already solved, old or not relevant anymore. Feel to open up a new issue if you're still experiencing this.