laravel/framework · error · InvalidArgumentException
Callback must be a callable, callback array, or a…
Error message
Callback must be a callable, callback array, or a 'Class@method' string.
What it means
Thrown by Gate::define() when the supplied callback is neither a PHP callable, an array whose first element is a class string, nor a 'Class@method' string. The Gate normalizes array callbacks to 'Class@method', stores string callbacks for lazy resolution, and callable values directly — anything else is rejected as a misconfiguration of an ability.
Solutions
- Pass a closure: Gate::define('update-post', fn (User $user, Post $post) => $user->id === $post->user_id);
- Pass a 'Class@method' string: Gate::define('update-post', 'PostPolicy@update');
- Pass a callable array with a class string first element: Gate::define('update-post', [PostPolicy::class, 'update']);
- Inspect the $callback variable at the call site to confirm its runtime type before calling define().
Example fix
// before
Gate::define('update-post', $policyInstance); // an object, not invokable
// after
Gate::define('update-post', [PostPolicy::class, 'update']);
// or
Gate::define('update-post', PostPolicy::class . '@update'); Defensive patterns
Strategy: validation
Validate before calling
// PHP — validate before Gate::define
function isValidGateCallback($callback): bool {
if (is_callable($callback)) return true;
if (is_string($callback)) return true;
if (is_array($callback) && isset($callback[0]) && is_string($callback[0])) return true;
return false;
}
if (! isValidGateCallback($cb)) {
throw new \InvalidArgumentException('Invalid gate callback supplied for ability.');
}
Gate::define($ability, $cb); Type guard
function isValidGateCallback($callback): bool {
return is_callable($callback)
|| is_string($callback)
|| (is_array($callback) && isset($callback[0]) && is_string($callback[0]));
} Try / catch
try {
Gate::define($ability, $callback);
} catch (\InvalidArgumentException $e) {
// log the ability + callback type for diagnosis
report(['ability' => $ability, 'type' => get_debug_type($callback), 'err' => $e->getMessage()]);
throw $e;
} Prevention
- Prefer closures or Class@method strings when defining abilities.
- Validate callback shape in config loaders before passing to Gate::define.
- Add static analysis (PHPStan) to ensure define() receives the expected callback type.
When it happens
Trigger: Calling Gate::define($ability, $callback) (or Authorizable::define / Auth::define via the gate facade) with a value such as null, an integer, an object that is not __invoke-able, or an array lacking a string class key.
Common situations: Passing a non-static method array ['SomeClass', 'method'] where the class entry was overwritten; passing a service-container-resolved instance by mistake instead of a class string; typos in 'Class@method' that produce a non-string after concatenation; passing null from an optional config value.
Related errors
- A driver must be specified.
- Auth driver [ ] for guard [ ] is not defined.
- Auth guard [ ] is not defined.
- Authentication user provider
- Broadcast connection
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/443e157e9176ad8b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Auth/Access/Gate.php:212
*
* @throws \InvalidArgumentException
*/
public function define($ability, $callback)
{
$ability = enum_value($ability);
if (is_array($callback) && isset($callback[0]) && is_string($callback[0])) {
$callback = $callback[0].'@'.$callback[1];
}
if (is_callable($callback)) {
$this->abilities[$ability] = $callback;
} elseif (is_string($callback)) {
$this->stringCallbacks[$ability] = $callback;
$this->abilities[$ability] = $this->buildAbilityCallback($ability, $callback);
} else {
throw new InvalidArgumentException("Callback must be a callable, callback array, or a 'Class@method' string.");
}
return $this;
}
/**
* Define abilities for a resource.
*
* @param string $name
* @param string $class
* @param array|null $abilities
* @return $this
*/
public function resource($name, $class, ?array $abilities = null)
{
$abilities = $abilities ?: [
'viewAny' => 'viewAny',
'view' => 'view',View on GitHub (pinned to e0f6eb3518)