w7corp/easywechat · error · HttpException
Failed to get jssdk ticket: %s
Error message
Failed to get jssdk ticket: %s
What it means
OfficialAccount\JsApiTicket::refreshTicket() fetches the JS-SDK ticket from /cgi-bin/ticket/getticket?type=jsapi over an access-token-aware client, caches it, and throws HttpException with the raw JSON when the response carries no ticket. The failure almost always originates in the credential layer (invalid or expired access_token), not in the ticket API itself.
Source
Thrown at src/OfficialAccount/JsApiTicket.php:36
$ticket = $this->cache->get($key);
if ($ticket && \is_string($ticket)) {
return $ticket;
}
return $this->refreshTicket();
}
/**
* @throws HttpException
*/
public function refreshTicket(): string
{
$response = $this->httpClient->request('GET', '/cgi-bin/ticket/getticket', ['query' => ['type' => 'jsapi']])
->toArray(false);
if (empty($response['ticket'])) {
throw new HttpException('Failed to get jssdk ticket: '.\json_encode($response, JSON_UNESCAPED_UNICODE));
}
$this->cache->set($this->getKey(), $response['ticket'], \intval($response['expires_in']));
return $response['ticket'];
}
/**
* @return array<string,mixed>
*/
#[ArrayShape([
'url' => 'string',
'nonceStr' => 'string',
'timestamp' => 'int',
'appId' => 'string',
'signature' => 'string',
])]
public function configSignature(string $url, string $nonce, int $timestamp): arrayView on GitHub (pinned to f0cf0a8b83)
Solutions
- Decode the embedded errcode: 40001 → credentials/access_token, 42001 → expired token
- Flush the cached access_token (clear the EasyWeChat cache keys) so it is re-fetched with current credentials, then retry the ticket call
- Verify appid/secret and IP whitelist exactly as for access_token failures
- Give each account its own cache prefix to avoid cross-app key collisions
Example fix
// before: retrying the ticket call while a stale access_token is cached $ticket = $app->getTicket()->getTicket(); // after: drop the stale token first, then refetch (ticket caches itself on success) $app->getCache()->clear(); // or delete the specific access_token key $ticket = $app->getTicket()->getTicket();
Defensive patterns
Strategy: try-catch
Try / catch
try {
$ticket = $app->getTicket()->getTicket();
} catch (\EasyWeChat\Kernel\Exceptions\HttpException $e) {
$payload = json_decode(strstr($e->getMessage(), '{') ?: '[]', true) ?: [];
if (in_array(($payload['errcode'] ?? null), [40001, 42001], true)) {
$app->getCache()->clear(); // drop stale access_token, next call refetches
$ticket = $app->getTicket()->getTicket();
} else {
report($e);
}
} Prevention
- After rotating a secret, flush the shared token cache in the same change
- Use per-account cache prefixes so tokens/tickets never collide
- Monitor ticket-fetch failures as a proxy for credential-layer health
When it happens
Trigger: Building JS-SDK signatures (ticket->getTicket() or utils building js-sdk config) while the underlying access_token is invalid (40001) or expired (42001); stale access_token still served from cache after a secret rotation; cache-key collisions between apps sharing one namespace.
Common situations: Secret changed but the cached access_token in Redis is still being served; two different official accounts sharing a cache prefix so tokens/tickets overwrite each other; wx.config pages breaking in bulk after credential changes.
Related errors
- Failed to get stable access_token: %s
- Failed to get access_token: %s
- Failed to get jssdk ticket: %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/2487689f1effe6cf.
Report an issue: GitHub.