SerializedQueuedModel
Emitted when a class implementing Illuminate\Contracts\Queue\ShouldQueue holds an Eloquent model (or an Eloquent\Collection) in a property, and the class has no __serialize() or __sleep() of its own, inherited, or brought in by a trait.
One report per class, on the class declaration, naming the offending properties (the first three of them). The fix is a single use SerializesModels;, so a per-property report would be several findings for one edit.
Enabled by default and reported at error levels 1 to 4, info at looser levels. Disable it with the findSerializedQueuedModels flag (see Configuration).
Why this is a problem
SerializesModels::__serialize() replaces each model with a ModelIdentifier and re-resolves it in __unserialize(). Without the trait, the whole model goes into the queue payload:
- the worker runs against a snapshot taken at dispatch time, not current data
- payloads grow with the model’s attributes and every loaded relation
- a payload written before a schema change can fail to unserialize after it
Examples
// Bad — the entire Customer, with whatever relations were loaded, is written into the payload
class SendCustomerReport implements ShouldQueue
{
use Queueable; // Illuminate\Bus\Queueable — no SerializesModels
public function __construct(public Customer $customer) {}
}
// Good — only a ModelIdentifier is serialized, and the worker reloads the row
class SendCustomerReport implements ShouldQueue
{
use Queueable;
use SerializesModels;
public function __construct(public Customer $customer) {}
}
What is not reported
A queued class that ends up with a __serialize() or __sleep(), whether from SerializesModels (directly, through a parent, or through a trait that itself uses it), from another trait, or hand-written. That covers Illuminate\Foundation\Queue\Queueable, which make:job scaffolds since Laravel 11, and Illuminate\Notifications\Notification.
Also silent: abstract classes, static properties, and properties inherited from a parent or declared by a trait.
Known blind spots, all in the safe direction:
- models held in a plain
array, andSupport\Collectionof models (not aQueueableCollection, so the trait would not convert it either) - queued event listeners, whose own properties never enter the payload: Laravel queues a
CallQueuedListenerwrapper and re-resolves the listener from the container
How to fix
Add use SerializesModels; to the queued class, or replace a hand-assembled trait list with Illuminate\Foundation\Queue\Queueable.
If a property deliberately holds a detached model that must survive as-is, suppress the issue in the class docblock with @psalm-suppress SerializedQueuedModel and say why in a comment. The report is class-level, so a property-level suppression does not reach it.