laravel/framework · error · LogicException

Please implement the prunable method on your model.

Error message

Please implement the prunable method on your model.

What it means

The MassPrunable trait provides a default prunable() method that only throws this LogicException. MassPrunable deletes records in bulk via a single query (chunked delete) and requires the consuming model to override prunable() to return the query builder that selects which records to remove. Without an override, pruneAll() cannot proceed.

Source

Thrown at src/Illuminate/Database/Eloquent/MassPrunable.php:50

            if ($count > 0) {
                event(new ModelsPruned(static::class, $total));
            }
        } while ($count > 0);

        return $total;
    }

    /**
     * Get the prunable model query.
     *
     * @return \Illuminate\Database\Eloquent\Builder<static>
     *
     * @throws \LogicException
     */
    public function prunable()
    {
        throw new LogicException('Please implement the prunable method on your model.');
    }
}

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Implement prunable() on the model returning a Builder, e.g. public function prunable() { return static::where('created_at', '<', now()->subYear()); }.
  2. If you intended per-model pruning logic, use the Prunable trait instead of MassPrunable.
  3. Ensure the method returns a Builder (not a collection) and includes the where conditions selecting rows to prune.

Example fix

// before
class LogEntry extends Model {
    use MassPrunable;
}

// after
class LogEntry extends Model {
    use MassPrunable;

    public function prunable()
    {
        return static::where('created_at', '<', now()->subMonth());
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

$reflection = new \ReflectionMethod($modelClass, 'prunable');
if ($reflection->getDeclaringClass()->getName() === \Illuminate\Database\Eloquent\MassPrunable::class) {
    throw new \LogicException("{$modelClass} must override prunable() before pruning.");
}

Type guard

function implementsPrunable(string $modelClass): bool {
    return (new \ReflectionMethod($modelClass, 'prunable'))
        ->getDeclaringClass()->getName() !== \Illuminate\Database\Eloquent\MassPrunable::class;
}

Prevention

When it happens

Trigger: Adding 'use MassPrunable;' to a model and then invoking Model::pruneAll() (typically via the model:prune artisan command) without overriding the prunable() method.

Common situations: Adopting the MassPrunable trait for faster pruning but forgetting the prunable() stub, or swapping from Prunable to MassPrunable and missing the override requirement.

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/39861b2b28dc9c41.json. Report an issue: GitHub.