w7corp/easywechat · error · InvalidArgumentException

The factory must return a %s instance.

Error message

The factory must return a %s instance.

What it means

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.

Source

Thrown at src/OfficialAccount/Application.php:179

    /**
     * @throws InvalidArgumentException
     */
    public function getOAuth(): SocialiteProviderInterface
    {
        if (! $this->oauthFactory) {
            $this->oauthFactory = fn (self $app): SocialiteProviderInterface => (new WeChat(
                [
                    'client_id' => $this->getAccount()->getAppId(),
                    'client_secret' => $this->getAccount()->getSecret(),
                    'redirect_url' => $this->config->get('oauth.redirect_url'),
                ]
            ))->scopes((array) $this->config->get('oauth.scopes', ['snsapi_userinfo']));
        }

        $provider = call_user_func($this->oauthFactory, $this);

        if (! $provider instanceof SocialiteProviderInterface) {
            throw new InvalidArgumentException(sprintf(
                'The factory must return a %s instance.',
                SocialiteProviderInterface::class
            ));
        }

        return $provider;
    }

    public function getTicket(): JsApiTicketInterface|RefreshableJsApiTicketInterface
    {
        if (! $this->ticket) {
            $this->ticket = new JsApiTicket(
                appId: $this->getAccount()->getAppId(),
                secret: $this->getAccount()->getSecret(),
                cache: $this->getCache(),
                httpClient: $this->getClient(),
                stable: $this->config->get('use_stable_access_token', false),
            );

View on GitHub (pinned to f0cf0a8b83)

Solutions

  1. Return the provider object from the factory closure, e.g. return (new WeChat([...]))->scopes([...])
  2. Implement Overtrue\Socialite\Contracts\ProviderInterface on the custom class
  3. Type the closure's return (fn (): ProviderInterface => ...) so PHP/static analysis rejects mismatches before runtime

Example fix

// before
$app->setOAuthFactory(fn ($app) => new MyCustomSso()); // not a Socialite provider

// after
$app->setOAuthFactory(
    fn ($app) => (new \Overtrue\Socialite\Providers\WeChat([
        'client_id'     => $app->getAccount()->getAppId(),
        'client_secret' => $app->getAccount()->getSecret(),
        'redirect_url'  => 'https://example.com/oauth/callback',
    ]))->scopes(['snsapi_userinfo'])
);
Defensive patterns

Strategy: type-guard

Type guard

function isSocialiteProvider(mixed $provider): bool
{
    return $provider instanceof \Overtrue\Socialite\Contracts\ProviderInterface;
}

$provider = ($factory)($app);
if (! isSocialiteProvider($provider)) {
    throw new \UnexpectedValueException(
        'OAuth factory returned '.get_debug_type($provider).', expected ProviderInterface.'
    );
}

Try / catch

try {
    $provider = $app->getOAuth();
} catch (\EasyWeChat\Kernel\Exceptions\InvalidArgumentException $e) {
    throw new \UnexpectedValueException('Custom OAuth factory must return a Socialite provider; got '.get_debug_type($factoryResult), 0, $e);
}

Prevention

When it happens

Trigger: 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.

Common situations: Swapping in a custom or extended WeChat provider; refactoring a closure so the return disappears; test factories returning mocks of the wrong interface.

Related errors


AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21). Data as JSON: /api/errors/800c70b1a312b3a8. Report an issue: GitHub.