{"record":{"id":"800c70b1a312b3a8","repo":"w7corp/easywechat","slug":"the-factory-must-return-a-s-instance","errorCode":null,"errorMessage":"The factory must return a %s instance.","messagePattern":"The factory must return a (.+?) instance\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/OfficialAccount/Application.php","lineNumber":179,"sourceCode":"    /**\n     * @throws InvalidArgumentException\n     */\n    public function getOAuth(): SocialiteProviderInterface\n    {\n        if (! $this->oauthFactory) {\n            $this->oauthFactory = fn (self $app): SocialiteProviderInterface => (new WeChat(\n                [\n                    'client_id' => $this->getAccount()->getAppId(),\n                    'client_secret' => $this->getAccount()->getSecret(),\n                    'redirect_url' => $this->config->get('oauth.redirect_url'),\n                ]\n            ))->scopes((array) $this->config->get('oauth.scopes', ['snsapi_userinfo']));\n        }\n\n        $provider = call_user_func($this->oauthFactory, $this);\n\n        if (! $provider instanceof SocialiteProviderInterface) {\n            throw new InvalidArgumentException(sprintf(\n                'The factory must return a %s instance.',\n                SocialiteProviderInterface::class\n            ));\n        }\n\n        return $provider;\n    }\n\n    public function getTicket(): JsApiTicketInterface|RefreshableJsApiTicketInterface\n    {\n        if (! $this->ticket) {\n            $this->ticket = new JsApiTicket(\n                appId: $this->getAccount()->getAppId(),\n                secret: $this->getAccount()->getSecret(),\n                cache: $this->getCache(),\n                httpClient: $this->getClient(),\n                stable: $this->config->get('use_stable_access_token', false),\n            );","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/OfficialAccount/Application.php#L161-L197","documentation":"Application::getOAuth() supports a custom OAuth provider factory via setOAuthFactory(). After invoking the factory it requires an instance of Overtrue\\Socialite\\Contracts\\ProviderInterface; anything else (another class, null, a builder object) triggers InvalidArgumentException. The guard exists because the rest of the OAuth flow (redirect(), userFromCode()) only works against the Socialite provider contract.","triggerScenarios":"setOAuthFactory(fn ($app) => new MyProvider(...)) where MyProvider does not implement ProviderInterface; a factory closure that forgets its return statement; a factory returning a config array or builder instead of the provider object.","commonSituations":"Swapping in a custom or extended WeChat provider; refactoring a closure so the return disappears; test factories returning mocks of the wrong interface.","solutions":["Return the provider object from the factory closure, e.g. return (new WeChat([...]))->scopes([...])","Implement Overtrue\\Socialite\\Contracts\\ProviderInterface on the custom class","Type the closure's return (fn (): ProviderInterface => ...) so PHP/static analysis rejects mismatches before runtime"],"exampleFix":"// before\n$app->setOAuthFactory(fn ($app) => new MyCustomSso()); // not a Socialite provider\n\n// after\n$app->setOAuthFactory(\n    fn ($app) => (new \\Overtrue\\Socialite\\Providers\\WeChat([\n        'client_id'     => $app->getAccount()->getAppId(),\n        'client_secret' => $app->getAccount()->getSecret(),\n        'redirect_url'  => 'https://example.com/oauth/callback',\n    ]))->scopes(['snsapi_userinfo'])\n);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isSocialiteProvider(mixed $provider): bool\n{\n    return $provider instanceof \\Overtrue\\Socialite\\Contracts\\ProviderInterface;\n}\n\n$provider = ($factory)($app);\nif (! isSocialiteProvider($provider)) {\n    throw new \\UnexpectedValueException(\n        'OAuth factory returned '.get_debug_type($provider).', expected ProviderInterface.'\n    );\n}","tryCatchPattern":"try {\n    $provider = $app->getOAuth();\n} catch (\\EasyWeChat\\Kernel\\Exceptions\\InvalidArgumentException $e) {\n    throw new \\UnexpectedValueException('Custom OAuth factory must return a Socialite provider; got '.get_debug_type($factoryResult), 0, $e);\n}","preventionTips":["Type the factory closure's return (fn (): ProviderInterface => ...) so mismatches fail statically","Keep custom providers as small adapters implementing ProviderInterface","Assert instanceof against the interface (not a concrete class) in tests"],"tags":["php","easywechat","oauth","socialite","factory","type-mismatch"],"backgroundTag":"invalid-factory-return-type","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}