laravel/framework · error · InvalidArgumentException
Global scope must be an instance of Closure or Scope or be a
Error message
Global scope must be an instance of Closure or Scope or be a class name of a class extending {Scope::class} What it means
addGlobalScope() accepts exactly four shapes: a Closure, a Scope instance, a Scope subclass name string, or a name string paired with a Closure/Scope implementation. Anything else (random string, non-Scope object, scalar) is rejected with InvalidArgumentException because the scope cannot be applied.
Source
Thrown at src/Illuminate/Database/Eloquent/Concerns/HasGlobalScopes.php:75
* @param \Illuminate\Database\Eloquent\Scope|(\Closure(\Illuminate\Database\Eloquent\Builder<static>): mixed)|string $scope
* @param \Illuminate\Database\Eloquent\Scope|(\Closure(\Illuminate\Database\Eloquent\Builder<static>): mixed)|null $implementation
* @return mixed
*
* @throws \InvalidArgumentException
*/
public static function addGlobalScope($scope, $implementation = null)
{
if (is_string($scope) && ($implementation instanceof Closure || $implementation instanceof Scope)) {
return static::$globalScopes[static::class][$scope] = $implementation;
} elseif ($scope instanceof Closure) {
return static::$globalScopes[static::class][spl_object_hash($scope)] = $scope;
} elseif ($scope instanceof Scope) {
return static::$globalScopes[static::class][get_class($scope)] = $scope;
} elseif (is_string($scope) && class_exists($scope) && is_subclass_of($scope, Scope::class)) {
return static::$globalScopes[static::class][$scope] = new $scope;
}
throw new InvalidArgumentException('Global scope must be an instance of Closure or Scope or be a class name of a class extending '.Scope::class);
}
/**
* Register multiple global scopes on the model.
*
* @param array $scopes
* @return void
*/
public static function addGlobalScopes(array $scopes)
{
foreach ($scopes as $key => $scope) {
if (is_string($key)) {
static::addGlobalScope($key, $scope);
} else {
static::addGlobalScope($scope);
}
}
}View on GitHub (pinned to bd6b5437e6)
Solutions
- Make the scope class implement Illuminate\Database\Eloquent\Scope (with apply(Builder,Model)).
- Pass a Closure: Model::addGlobalScope(fn (Builder $b) => $b->where('active', 1)).
- If using a string class, ensure it extends/implements Scope and the class is autoloadable.
Example fix
// before
Model::addGlobalScope('active', \App\Scopes\ActiveScope::class);
// ActiveScope does not implement Scope
// after
class ActiveScope implements \Illuminate\Database\Eloquent\Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->where('active', true);
}
} Defensive patterns
Strategy: type-guard
Validate before calling
use Illuminate\Database\Eloquent\Scope;
if ($scope instanceof \Closure || $scope instanceof Scope) {
Model::addGlobalScope($name, $scope);
} elseif (is_string($scope) && is_subclass_of($scope, Scope::class)) {
Model::addGlobalScope($scope);
} else {
throw new \InvalidArgumentException('Invalid global scope: ' . get_debug_type($scope));
} Type guard
function isValidScope(mixed $scope): bool
{
return $scope instanceof \Closure
|| $scope instanceof \Illuminate\Database\Eloquent\Scope
|| (is_string($scope) && is_subclass_of($scope, \Illuminate\Database\Eloquent\Scope::class));
} Try / catch
try {
Model::addGlobalScope($name, $impl);
} catch (\InvalidArgumentException $e) {
if (str_contains($e->getMessage(), 'Global scope must be')) {
report('Invalid scope registration: ' . get_debug_type($impl));
}
throw $e;
} Prevention
- Implement Scope (with apply()) on scope classes; do not just name them 'scope'.
- Prefer Closures for one-off scopes and Scope instances for reusable ones.
- Add a unit test asserting each global scope class implements Scope.
When it happens
Trigger: Calling Model::addGlobalScope('active', 'App\Scopes\MissingScope') where the class does not extend Scope or does not exist; passing an object that is not a Scope; passing a string that is not a class with no implementation argument.
Common situations: Custom scope class forgetting to implement Illuminate\Database\Eloquent\Scope; passing a query-builder macro or a callable array (['Obj','method']) which is not a Closure; refactoring that dropped the Scope interface.
Related errors
- The provided class must extend [{Collection::class}].
- The provided class must extend [{Collection::class}].
- Unable to create query for collection with mixed types.
- %s::%s must return a relationship instance.
- The cast object for the {$attribute} attribute must implemen
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/7dfb8084281a172f.json.
Report an issue: GitHub.