laravel/framework · error · InvalidArgumentException

Global scope must be an instance of Closure or Scope or be…

Error message

Global scope must be an instance of Closure or Scope or be a class name of a class extending Illuminate\Database\Eloquent\Scope

What it means

Thrown by Model::addGlobalScope() when the arguments do not match any accepted signature. addGlobalScope accepts: a (string identifier, Closure|Scope) pair, a lone Closure, a lone Scope instance, or a string class name of a Scope subclass. Any other combination (e.g. a string with a non-Scope implementation, a random object, or a class string that is not a Scope subclass) hits the final else and throws.

Solutions

  1. Make a class-based scope extend Illuminate\Database\Eloquent\Scope and implement apply($builder, $model).
  2. Pass a Closure as the implementation when using a string identifier: addGlobalScope('active', fn (Builder $q) => $q->where('active', true)).
  3. Pass a single Scope instance: addGlobalScope(new ActiveScope).
  4. Double-check argument order and types against the four accepted signatures.

Example fix

// before
User::addGlobalScope('active', 'where active = 1'); // string is not Closure|Scope

// after
User::addGlobalScope('active', function (Builder $query) {
    $query->where('active', true);
});
Defensive patterns

Strategy: validation

Validate before calling

use Illuminate\Database\Eloquent\Scope;
use Closure;

$scope = 'active';
$impl = fn (\Illuminate\Database\Eloquent\Builder $q) => $q->where('active', true);

$ok = (is_string($scope) && ($impl instanceof Closure || $impl instanceof Scope))
    || $scope instanceof Closure
    || $scope instanceof Scope
    || (is_string($scope) && class_exists($scope) && is_subclass_of($scope, Scope::class));

if (! $ok) {
    throw new \LogicException('Invalid global scope signature');
}
User::addGlobalScope($scope, $impl);

Type guard

function isValidScopeSignature(mixed $scope, mixed $implementation = null): bool
{
    if (is_string($scope) && ($implementation instanceof \Closure || $implementation instanceof \Illuminate\Database\Eloquent\Scope)) {
        return true;
    }
    if ($scope instanceof \Closure || $scope instanceof \Illuminate\Database\Eloquent\Scope) {
        return true;
    }
    return is_string($scope) && class_exists($scope) && is_subclass_of($scope, \Illuminate\Database\Eloquent\Scope::class);
}

Prevention

When it happens

Trigger: Calling addGlobalScope('name', $notAClosureOrScope); addGlobalScope(SomeClass::class) where SomeClass does not extend Illuminate\Database\Eloquent\Scope; addGlobalScope($string, $string); or passing an instance whose class is not a Scope. The check cascade rejects all of these.

Common situations: Refactoring a scope from a Closure to a class but forgetting to make it extend Scope; passing a builder macro or query callback where a Scope is expected; passing a string identifier without a corresponding implementation; namespace mismatch on a Scope subclass.

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/c8ca1cff330e2c6c. Report an issue: GitHub.

Appendix: 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 e0f6eb3518)