laravel/framework · error · EntityNotFoundException
Queueable entity [{$type}] not found for ID [{$id}].
Error message
Queueable entity [{$type}] not found for ID [{$id}]. What it means
QueueEntityResolver.resolve() is used when a queued job serializes an Eloquent model by reference (ModelIdentifier) and Laravel re-fetches it on unserialization. If (new $type)->find($id) returns null - the row was deleted, the ID is wrong, or the model class changed - it throws EntityNotFoundException with the type and id.
Source
Thrown at src/Illuminate/Database/Eloquent/QueueEntityResolver.php:27
{
/**
* Resolve the entity for the given ID.
*
* @param string $type
* @param mixed $id
* @return mixed
*
* @throws \Illuminate\Contracts\Queue\EntityNotFoundException
*/
public function resolve($type, $id)
{
$instance = (new $type)->find($id);
if ($instance) {
return $instance;
}
throw new EntityNotFoundException($type, $id);
}
}
View on GitHub (pinned to e0f6eb3518)
Solutions
- Catch \Illuminate\Contracts\Queue\EntityNotFoundException in the job's handle() and skip/retry/abort gracefully.
- Pass the scalar ID (or a DTO) into the job instead of the model and re-fetch with findOrFail inside handle() so you control the missing-row behavior.
- Use the SerializesModels trait (default) so the model is re-resolved; ensure the row still exists at runtime or handle its absence.
- For soft-deleted models, fetch with withTrashed() in the job.
Example fix
// before - dispatching the model
ProcessReport::dispatch($user);
// later, user row deleted -> unserialize throws
// after - pass ID, fetch in handle()
class ProcessReport implements ShouldQueue {
public function __construct(public int $userId) {}
public function handle() {
$user = User::find($this->userId);
throw_unless($user, new \RuntimeException('User missing'));
// ...
}
}
ProcessReport::dispatch($user->id); Defensive patterns
Strategy: try-catch
Validate before calling
// Prefer passing scalar IDs into jobs and re-fetch inside handle()
// Validate existence at the boundary before dispatch:
if (! User::whereKey($userId)->exists()) {
throw new \RuntimeException("Cannot dispatch: user {$userId} missing");
}
ProcessJob::dispatch($userId); Type guard
function entityExists(string $type, mixed $id): bool {
return (new $type)->whereKey($id)->exists();
} Try / catch
try {
// job body that resolves the model
$user = User::findOrFail($id);
} catch (\Illuminate\Contracts\Queue\EntityNotFoundException $e) {
// row gone between dispatch and run - skip or requeue
$this->release(60); // or delete()
} Prevention
- Pass scalar IDs into queued jobs; fetch inside handle() with findOrFail to control missing-row behaviour.
- Catch EntityNotFoundException and decide skip/retry/fail rather than letting it bubble.
- Avoid long delays between dispatch and processing when the underlying row can be deleted.
- For soft-deleted models, fetch with withTrashed() in the job.
When it happens
Trigger: Dispatching a queued job with a model in its constructor, then deleting that model's row before the worker picks the job up; passing an unserialized/soft-deleted model id; model class rename leaving $type pointing at a stale class.
Common situations: Race between a delete and a queued worker; long-running queues holding stale references; deleting then re-running a queue:work; CI using an in-memory DB across processes; soft-deleted models without withTrashed on resolution.
Related errors
- Queueing collections with multiple model types is not suppor
- Queueing collections with multiple model connections is not
- Queue resolver did not return a Queue implementation.
- Attempted to batch job [%s], but it does not use the Batchab
- To enable support for closure jobs, please install the illum
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/6be3dcdd113facf5.
Report an issue: GitHub.