w7corp/easywechat · critical · HttpException
Failed to get component_access_token: %s
Error message
Failed to get component_access_token: %s
What it means
ComponentAccessToken fetches the component_access_token by POSTing component appid, secret and the current component_verify_ticket to cgi-bin/component/api_component_token, then caches it (expires_in minus 100 seconds). HttpException with the embedded JSON is thrown when WeChat returns no component_access_token — one of the three ingredients was rejected. Every open-platform API call depends on this token, so the whole component goes down when it fails.
Source
Thrown at src/OpenPlatform/ComponentAccessToken.php:86
/**
* @throws HttpException
*/
public function refresh(): string
{
$response = $this->httpClient->request(
'POST',
'cgi-bin/component/api_component_token',
[
'json' => [
'component_appid' => $this->appId,
'component_appsecret' => $this->secret,
'component_verify_ticket' => $this->verifyTicket->getTicket(),
],
]
)->toArray(false);
if (empty($response['component_access_token'])) {
throw new HttpException('Failed to get component_access_token: '.json_encode(
$response,
JSON_UNESCAPED_UNICODE
));
}
$this->cache->set(
$this->getKey(),
$response['component_access_token'],
abs(intval($response['expires_in']) - 100)
);
return $response['component_access_token'];
}
}
View on GitHub (pinned to f0cf0a8b83)
Solutions
- Decode the embedded errcode/errmsg — invalid-secret and invalid-ticket codes point to different fixes
- Fix the component secret in config if it was rotated, then redeploy/clear config cache
- Ensure verify-ticket pushes land on the shared cache so the freshest ticket is always used
- Retry after the next ticket push if the cache was stale
Example fix
// before: per-instance file cache → consumers read a stale component_verify_ticket → 40001 cycle $openPlatform->setCache(new \Symfony\Component\Cache\Adapter\FilesystemAdapter()); // after: shared Redis for both the push receiver and every worker $openPlatform->setCache(new \Symfony\Component\Cache\Adapter\RedisAdapter($redis, 'easywechat'));
Defensive patterns
Strategy: try-catch
Validate before calling
if (blank($config['component_appid'] ?? null) || blank($config['component_secret'] ?? null)) {
throw new \RuntimeException('OpenPlatform component appid/secret must be set.');
} Try / catch
try {
$token = $componentAccessToken->getToken();
} catch (\EasyWeChat\Kernel\Exceptions\HttpException $e) {
$payload = json_decode(strstr($e->getMessage(), '{') ?: '[]', true) ?: [];
$errcode = $payload['errcode'] ?? null;
// 40001 → stale verify ticket (check push receiver + shared cache); 40125-class → secret
report($e);
} Prevention
- Share one Redis (same prefix) between the ticket receiver and all component-token consumers
- Rotate the component secret in console and env in one change, then flush caches
- Treat repeated 40001s on this endpoint as 'ticket pushes stopped arriving', not random failure
When it happens
Trigger: component_verify_ticket stale (cache holds an old push while WeChat rotated it); wrong component_appid/component_appsecret; the ticket cache wiped mid-flight so the ticket used is empty/old; the component app not approved or frozen.
Common situations: Secret rotated in the console but not in env; file/local caches not shared so consumers read an old ticket; deploys switching Redis or changing cache prefixes; new component apps before their first ticket push arrives.
Related errors
- Failed to get stable access_token: %s
- Failed to get access_token: %s
- No component_verify_ticket found.
- Failed to get jssdk ticket: %s
- Failed to get authorization_info: %s
AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21).
Data as JSON: /api/errors/f75043f04670a5a0.
Report an issue: GitHub.