w7corp/easywechat · critical · HttpException
Failed to get access_token: %s
Error message
Failed to get access_token: %s
What it means
OfficialAccount\AccessToken::getAccessToken() is the classic token path: it GETs cgi-bin/token with grant_type=client_credential and the appid/secret, then throws HttpException with the raw JSON when no access_token comes back. WeChat rejected the client credentials or the calling IP. Every authenticated API call funnels through this token, so this failure blocks the whole account.
Source
Thrown at src/OfficialAccount/AccessToken.php:123
/**
* @throws HttpException
*/
public function getAccessToken(): string
{
$response = $this->httpClient->request(
'GET',
'cgi-bin/token',
[
'query' => [
'grant_type' => 'client_credential',
'appid' => $this->appId,
'secret' => $this->secret,
],
]
)->toArray(false);
if (empty($response['access_token'])) {
throw new HttpException('Failed to get access_token: '.json_encode($response, JSON_UNESCAPED_UNICODE));
}
$this->cache->set($this->getKey(), $response['access_token'], intval($response['expires_in']));
return $response['access_token'];
}
}
View on GitHub (pinned to f0cf0a8b83)
Solutions
- json_decode the embedded JSON and act on errcode (40125/41004 → secret, 40013 → appid, 40164 → IP whitelist)
- Whitelist the production egress IP in MP console → 基本配置 → IP名单
- Fix the env/config values and clear the app config cache, then retry
- Confirm you are not mixing the appid of one account with the secret of another
Example fix
// before: env key typo → empty secret sent to WeChat
$config = ['app_id' => env('WECHAT_APP_ID'), 'secret' => env('WECHAT_SECRET')];
// after
$config = ['app_id' => env('WECHAT_APP_ID'), 'secret' => env('WECHAT_OFFICIAL_ACCOUNT_SECRET')]; Defensive patterns
Strategy: try-catch
Validate before calling
if (blank($app->getConfig()->get('app_id')) || blank($app->getConfig()->get('secret'))) {
throw new \RuntimeException('OfficialAccount app_id/secret must be set before token requests.');
} Try / catch
try {
$token = $accessToken->getAccessToken();
} catch (\EasyWeChat\Kernel\Exceptions\HttpException $e) {
$payload = json_decode(strstr($e->getMessage(), '{') ?: '[]', true) ?: [];
// 40164 → whitelist IP; 40125/41004 → secret; 40013 → appid. Map each to a specific alert.
report($e);
} Prevention
- Resolve the egress IP for each deployment target and whitelist it before go-live
- Name env keys explicitly per account to avoid cross-env secret drift
- Smoke-test token retrieval in a deploy check so credential failures surface at deploy time, not at runtime
When it happens
Trigger: Wrong appid or secret in config; server egress IP missing from the MP console IP whitelist (errcode 40164); secret rotated in the console but not in env; daily token quota/IP changes after infrastructure moves.
Common situations: Works locally but fails in production (different egress IP); credential drift between environments; containerized deployments with NAT'd IPs nobody whitelisted; env var typo (WECHAT_SECRET vs WECHAT_OFFICIAL_ACCOUNT_SECRET).
Related errors
- Failed to get stable access_token: %s
- Failed to get jssdk ticket: %s
- Failed to get component_access_token: %s
- No secret configured.
- token or aes_key cannot be empty.
AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21).
Data as JSON: /api/errors/a9de781f19adb79a.
Report an issue: GitHub.