{"record":{"id":"05a93e8c7a5049cf","repo":"w7corp/easywechat","slug":"invalid-handler-s-05a93e","errorCode":null,"errorMessage":"Invalid handler: %s.","messagePattern":"Invalid handler: (.+?)\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Kernel/Traits/InteractWithHandlers.php","lineNumber":98,"sourceCode":"    /**\n     * @throws InvalidArgumentException\n     */\n    protected function makeClosure(callable|string $handler): callable\n    {\n        if (is_callable($handler)) {\n            return $handler;\n        }\n\n        if (class_exists($handler) && method_exists($handler, '__invoke')) {\n            /**\n             * @psalm-suppress InvalidFunctionCall\n             *\n             * @phpstan-ignore-next-line https://github.com/phpstan/phpstan/issues/5867\n             */\n            return fn (): mixed => (new $handler)(...func_get_args());\n        }\n\n        throw new InvalidArgumentException(sprintf('Invalid handler: %s.', $handler));\n    }\n\n    public function prepend(callable|string $handler): static\n    {\n        return $this->prependHandler($handler);\n    }\n\n    public function prependHandler(callable|string $handler): static\n    {\n        array_unshift($this->handlers, $this->createHandlerItem($handler));\n\n        return $this;\n    }\n\n    /**\n     * @throws InvalidArgumentException\n     */\n    public function without(callable|string $handler): static","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/Kernel/Traits/InteractWithHandlers.php#L80-L116","documentation":"makeClosure() resolves a string handler: it must either be callable (a function name or 'Class::staticMethod') or name an existing, autoloadable class that has __invoke. Anything else throws this InvalidArgumentException containing the original string. This is the path used when registering handlers by class name, e.g. $server->withHandler(NotifyHandler::class) or ->withHandler('App\\Handlers\\TextHandler').","triggerScenarios":"withHandler(SomeHandler::class) where SomeHandler has no __invoke method; a typo'd class name ('TextHander'); the class exists but is not autoloadable in the runtime (stale composer autoload); Laravel-style 'App\\Handler@handle' strings, which this SDK does not support.","commonSituations":"Copy-pasting handler registration from another app with different namespaces; new handler classes created but composer dump-autoload not run; refactors renaming classes without updating string-based registrations.","solutions":["If registering by class name, add public function __invoke(...) to the class.","Fix the class string (correct namespace + spelling) and run composer dump-autoload.","For instance or non-static methods, use a closure or [new Handler, 'method'].","Replace 'Class@method' syntax with a closure or a real invokable class."],"exampleFix":"// before: class has no __invoke\n$server->withHandler(NotifyHandler::class);\n// after: make the handler invokable\nfinal class NotifyHandler {\n    public function __invoke(Message $message, Closure $next): mixed { return $next($message); }\n}\n$server->withHandler(NotifyHandler::class);","handlingStrategy":"validation","validationCode":"if (!is_callable($h) && !(is_string($h) && class_exists($h) && method_exists($h, '__invoke'))) { throw new InvalidArgumentException('Unsupported handler string: '.$h); }\n$server->withHandler($h);","typeGuard":"function isInvokableHandler(string $h): bool { return is_callable($h) || (class_exists($h) && method_exists($h, '__invoke')); }","tryCatchPattern":"try { $server->withHandler($handler); } catch (\\EasyWeChat\\Kernel\\Exceptions\\InvalidArgumentException $e) { throw new RuntimeException('Handler \"'.$handler.'\" is neither callable nor an invokable class (typo? missing __invoke? stale autoload?)', 0, $e); }","preventionTips":["Give every handler class a public __invoke by convention","Run composer dump-autoload after adding handler classes","Cover handler registration in a boot smoke test"],"tags":["php","handlers","invokable","autoload"],"backgroundTag":"invalid-callback-handler","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}