w7corp/easywechat · error · HttpException

Failed to get suite_access_token: %s

Error message

Failed to get suite_access_token: %s

What it means

Thrown by SuiteAccessToken::refresh() when the POST to cgi-bin/service/get_suite_token returns a body without suite_access_token. The suite token requires three correct inputs: suite_id, suite_secret, and a valid suite_ticket pushed by WeChat every ~10 minutes to your callback URL. The raw response with errcode is JSON-embedded in the message.

Source

Thrown at src/OpenWork/SuiteAccessToken.php:88

    {
        return ['suite_access_token' => $this->getToken()];
    }

    /**
     * @throws HttpException
     */
    public function refresh(): string
    {
        $response = $this->httpClient->request('POST', 'cgi-bin/service/get_suite_token', [
            'json' => [
                'suite_id' => $this->suiteId,
                'suite_secret' => $this->suiteSecret,
                'suite_ticket' => $this->suiteTicket?->getTicket(),
            ],
        ])->toArray(false);

        if (empty($response['suite_access_token'])) {
            throw new HttpException('Failed to get suite_access_token: '.json_encode(
                $response,
                JSON_UNESCAPED_UNICODE
            ));
        }

        $this->cache->set(
            $this->getKey(),
            $response['suite_access_token'],
            abs(intval($response['expires_in']) - 100)
        );

        return $response['suite_access_token'];
    }
}

View on GitHub (pinned to f0cf0a8b83)

Solutions

  1. Check embedded errcode in the exception message (61004/61003 = ticket problem, 40001 = secret problem)
  2. Confirm the suite_ticket callback (data type 'suite_ticket') is configured and reachable, and that SuiteTicket::setTicket() is being called from your callback handler
  3. Verify suite_id and suite_secret match the same suite in the open platform console
  4. If tickets are pushed but still failing, ensure cache is shared/persistent across the callback process and the API process

Example fix

// in your OpenWork callback controller, persist the pushed ticket
// before
$server->serve(); // ticket never saved
// after
$server->handle('suite_ticket', function (Message $message, SuiteTicket $suiteTicket) {
    $suiteTicket->setTicket($message->SuiteTicket, $message->info expiresIn);
    return 'success';
});
return $server->serve();
Defensive patterns

Strategy: retry

Validate before calling

try {
    $suiteTicket->getTicket(); // ticket present?
} catch (\EasyWeChat\Kernel\Exceptions\RuntimeException $e) {
    // ticket not pushed yet - wait for next push
}

Try / catch

use EasyWeChat\Kernel\Exceptions\HttpException;
try {
    $token = $openWork->suite_access_token->getToken();
} catch (HttpException $e) {
    if (str_contains($e->getMessage(), '61004') || str_contains($e->getMessage(), 'suite_ticket')) {
        // wait for next ticket push (<=10 min) then retry once
        retryIn(600, fn () => $openWork->suite_access_token->getToken());
    }
    throw $e;
}

Prevention

When it happens

Trigger: Any OpenWork API call needing suite_access_token (e.g. get_auth_corpa_info, get_corp_token) on cache miss. Fails when suite_id/suite_secret mismatch, or the suite_ticket is missing, stale, or belongs to another suite (errcode 40001, 40013, 61004 'invalid suite_ticket').

Common situations: Callback URL for receiving suite_ticket not configured or not reachable (so the ticket never lands in cache); cache driver flushed/short TTL so the ticket expired; using the suite_ticket of one suite with credentials of another; ticket overwritten by multiple suites sharing one cache key prefix.

Related errors


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