w7corp/easywechat · error · HttpException
code2Session error: %s
Error message
code2Session error: %s
What it means
Utils::codeToSession() calls GET /sns/jscode2session and expects openid in the response; WeChat reports failures with errcode inside an HTTP 200 body (40029 invalid js_code, 40163 code already used, 45011 frequency limit, -1 system busy), so any response without openid becomes HttpException with the full JSON appended. This is the exchange step of mini-program login (wx.login code → openid + session_key).
Source
Thrown at src/MiniApp/Utils.php:28
{
}
/**
* @throws HttpException
*/
public function codeToSession(string $code): array
{
$response = $this->app->getHttpClient()->request('GET', '/sns/jscode2session', [
'query' => [
'appid' => $this->app->getAccount()->getAppId(),
'secret' => $this->app->getAccount()->getSecret(),
'js_code' => $code,
'grant_type' => 'authorization_code',
],
])->toArray(false);
if (empty($response['openid'])) {
throw new HttpException('code2Session error: '.json_encode($response, JSON_UNESCAPED_UNICODE));
}
return $response;
}
public function decryptSession(string $sessionKey, string $iv, string $ciphertext): array
{
return Decryptor::decrypt($sessionKey, $iv, $ciphertext);
}
/**
* @throws HttpException
*/
public function getPhoneNumber(string $code): array
{
$response = $this->app->createClient()->request('POST', '/wxa/business/getuserphonenumber', [
'json' => [
'code' => $code,View on GitHub (pinned to f0cf0a8b83)
Solutions
- Use each js_code exactly once, immediately after wx.login; request a fresh code on failure.
- Confirm appid and secret come from the same mini program console entry and are current (re-copy the secret).
- Decode the JSON inside the exception message and branch on errcode: 40029/40163 → ask the client for a new code; -1/45011 → retry with backoff.
- Cache openid/session_key briefly after a successful exchange so retries do not re-exchange codes.
Example fix
// before: replaying a consumed js_code
$session = $app->getUtils()->codeToSession($sameOldCode);
// after: branch on errcode and request a fresh code when invalid
try {
$session = $app->getUtils()->codeToSession($code);
} catch (HttpException $e) {
if (str_contains($e->getMessage(), '40029')) {
return $this->askClientForNewCode();
}
throw $e;
} Defensive patterns
Strategy: retry
Validate before calling
$code = trim($code);
if ($code === '') { throw new InvalidArgumentException('js_code required'); }
if (!Cache::add('js_code:'.$code, 1, 300)) { throw new RuntimeException('code already consumed'); } Try / catch
try { $session = $app->getUtils()->codeToSession($code); } catch (\EasyWeChat\Kernel\Exceptions\HttpException $e) { $body = json_decode(substr($e->getMessage(), (int) strpos($e->getMessage(), '{')), true); $err = (int) ($body['errcode'] ?? 0); if (in_array($err, [-1, 45011], true)) { usleep(500000); return $app->getUtils()->codeToSession($code); } // 40029/40163: ask the client for a fresh wx.login code throw new DomainException('wx login rejected: errcode '.$err); } Prevention
- Mark codes consumed (idempotency key) before exchanging
- Keep appid/secret as one deployable unit
- Retry only transient errcodes (-1, 45011) with backoff
- Log the full response JSON on every failure
When it happens
Trigger: Exchanging a js_code twice (codes are single-use and short-lived); appid+secret pair mismatched (secret from another app, or reset in the console); calling jscode2session beyond the per-minute quota (45011); appid belonging to a different mini program than the code; empty secret because env vars differ per environment.
Common situations: WeChat dev tools (test appid) against a production secret; page refresh replaying the login with the same code; load tests tripping 45011; secret rotated in the console but not redeployed.
Related errors
- token or aes_key cannot be empty.
- The given payload is invalid.
- The given payload is invalid: %s
- getPhoneNumber error: %s
- "%s" cannot be empty.\r\n
AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21).
Data as JSON: /api/errors/22506a9d824dad1d.
Report an issue: GitHub.