{"id":"443e157e9176ad8b","repo":"laravel/framework","slug":"callback-must-be-a-callable-callback-array-or-a","errorCode":null,"errorMessage":"Callback must be a callable, callback array, or a 'Class@method' string.","messagePattern":"Callback must be a callable, callback array, or a 'Class@method' string\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Auth/Access/Gate.php","lineNumber":212,"sourceCode":"     *\n     * @throws \\InvalidArgumentException\n     */\n    public function define($ability, $callback)\n    {\n        $ability = enum_value($ability);\n\n        if (is_array($callback) && isset($callback[0]) && is_string($callback[0])) {\n            $callback = $callback[0].'@'.$callback[1];\n        }\n\n        if (is_callable($callback)) {\n            $this->abilities[$ability] = $callback;\n        } elseif (is_string($callback)) {\n            $this->stringCallbacks[$ability] = $callback;\n\n            $this->abilities[$ability] = $this->buildAbilityCallback($ability, $callback);\n        } else {\n            throw new InvalidArgumentException(\"Callback must be a callable, callback array, or a 'Class@method' string.\");\n        }\n\n        return $this;\n    }\n\n    /**\n     * Define abilities for a resource.\n     *\n     * @param  string  $name\n     * @param  string  $class\n     * @param  array|null  $abilities\n     * @return $this\n     */\n    public function resource($name, $class, ?array $abilities = null)\n    {\n        $abilities = $abilities ?: [\n            'viewAny' => 'viewAny',\n            'view' => 'view',","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Auth/Access/Gate.php#L194-L230","documentation":"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 rejects any other type so that ability resolution never silently stores an unusable handler.","triggerScenarios":"Calling Gate::define('update', $someValue) where $someValue is null, an integer, an object that is not callable, or a malformed array like ['Class', 123]; also triggered indirectly through Gate::resource() when the class argument is not a string.","commonSituations":"Passing a non-existent class@method string that resolves to a non-callable, passing null when a policy class was expected, or a typo where a variable holding a closure is accidentally overwritten before define().","solutions":["Verify the callback is a Closure/callable, a ['Class','method'] array, or a 'Class@method' string before calling define().","If referencing a class string, confirm the class exists and the method is public.","Use Gate::policy() or a policy class mapping instead of manual define() when authorizing models.","Add a unit test that asserts is_callable($callback) (or Str::parseCallback validity) for dynamic registrations."],"exampleFix":"// before\nGate::define('update-post', $maybeNull);\n\n// after\nuse Illuminate\\Support\\Str;\n\nif (is_callable($maybeNull) || Str::parseCallback($maybeNull) !== [null, null]) {\n    Gate::define('update-post', $maybeNull);\n}","handlingStrategy":"validation","validationCode":"use Illuminate\\Support\\Str;\n\nfunction isValidGateCallback($callback): bool\n{\n    return is_callable($callback)\n        || (is_string($callback) && Str::parseCallback($callback) !== [null, null])\n        || (is_array($callback) && isset($callback[0], $callback[1]) && is_string($callback[0]));\n}\n\nif (! isValidGateCallback($cb)) {\n    throw new InvalidArgumentException('Refusing to define ability with invalid callback.');\n}","typeGuard":"function isGateCallback(mixed $callback): bool\n{\n    return is_callable($callback) || is_string($callback);\n}","tryCatchPattern":"try {\n    Gate::define('update-post', $callback);\n} catch (\\InvalidArgumentException $e) {\n    // log which ability/callback failed registration and fall back to a policy\n    logger()->error('Invalid Gate callback', ['message' => $e->getMessage()]);\n}","preventionTips":["Validate dynamic callbacks with is_callable()/Str::parseCallback before calling Gate::define().","Prefer policy classes over manual define() for model authorization.","Cover dynamic ability registration with a unit test asserting no InvalidArgumentException."],"tags":["authorization","gate","laravel","configuration","callable"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}