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
- Check embedded errcode in the exception message (61004/61003 = ticket problem, 40001 = secret problem)
- Confirm the suite_ticket callback (data type 'suite_ticket') is configured and reachable, and that SuiteTicket::setTicket() is being called from your callback handler
- Verify suite_id and suite_secret match the same suite in the open platform console
- 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
- Persist suite_ticket in shared durable cache (Redis) from the callback handler
- Monitor the callback endpoint so pushes never 5xx
- Do not run multiple suites on overlapping cache key prefixes
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
- Failed to get provider_access_token: %s
- No suite_ticket found.
- Failed to get auth_corp_info: %s
- Failed to get access_token: %s
- Failed to get jssdk ticket: %s
AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21).
Data as JSON: /api/errors/94380e66fb167433.
Report an issue: GitHub.