{"record":{"id":"2487689f1effe6cf","repo":"w7corp/easywechat","slug":"failed-to-get-jssdk-ticket-s","errorCode":null,"errorMessage":"Failed to get jssdk ticket: %s","messagePattern":"Failed to get jssdk ticket: (.+?)","errorType":"exception","errorClass":"HttpException","httpStatus":null,"severity":"error","filePath":"src/OfficialAccount/JsApiTicket.php","lineNumber":36,"sourceCode":"        $ticket = $this->cache->get($key);\n\n        if ($ticket && \\is_string($ticket)) {\n            return $ticket;\n        }\n\n        return $this->refreshTicket();\n    }\n\n    /**\n     * @throws HttpException\n     */\n    public function refreshTicket(): string\n    {\n        $response = $this->httpClient->request('GET', '/cgi-bin/ticket/getticket', ['query' => ['type' => 'jsapi']])\n            ->toArray(false);\n\n        if (empty($response['ticket'])) {\n            throw new HttpException('Failed to get jssdk ticket: '.\\json_encode($response, JSON_UNESCAPED_UNICODE));\n        }\n\n        $this->cache->set($this->getKey(), $response['ticket'], \\intval($response['expires_in']));\n\n        return $response['ticket'];\n    }\n\n    /**\n     * @return array<string,mixed>\n     */\n    #[ArrayShape([\n        'url' => 'string',\n        'nonceStr' => 'string',\n        'timestamp' => 'int',\n        'appId' => 'string',\n        'signature' => 'string',\n    ])]\n    public function configSignature(string $url, string $nonce, int $timestamp): array","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/OfficialAccount/JsApiTicket.php#L18-L54","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: retrying the ticket call while a stale access_token is cached\n$ticket = $app->getTicket()->getTicket();\n\n// after: drop the stale token first, then refetch (ticket caches itself on success)\n$app->getCache()->clear(); // or delete the specific access_token key\n$ticket = $app->getTicket()->getTicket();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    $ticket = $app->getTicket()->getTicket();\n} catch (\\EasyWeChat\\Kernel\\Exceptions\\HttpException $e) {\n    $payload = json_decode(strstr($e->getMessage(), '{') ?: '[]', true) ?: [];\n    if (in_array(($payload['errcode'] ?? null), [40001, 42001], true)) {\n        $app->getCache()->clear(); // drop stale access_token, next call refetches\n        $ticket = $app->getTicket()->getTicket();\n    } else {\n        report($e);\n    }\n}","preventionTips":["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"],"tags":["php","easywechat","wechat","official-account","jsapi-ticket","js-sdk","access-token"],"backgroundTag":"jsapi-ticket-fetch-failed","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}