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): array

View on GitHub (pinned to f0cf0a8b83)

Solutions

  1. Decode the embedded errcode: 40001 → credentials/access_token, 42001 → expired token
  2. Flush the cached access_token (clear the EasyWeChat cache keys) so it is re-fetched with current credentials, then retry the ticket call
  3. Verify appid/secret and IP whitelist exactly as for access_token failures
  4. 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

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


AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21). Data as JSON: /api/errors/2487689f1effe6cf. Report an issue: GitHub.