{"record":{"id":"9729868a7f0d4880","repo":"w7corp/easywechat","slug":"failed-to-get-jssdk-ticket-s-972986","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/OpenWork/JsApiTicket.php","lineNumber":71,"sourceCode":"        return sha1(sprintf('jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s', $ticket, $nonce, $timestamp, $url));\n    }\n\n    /**\n     * @throws HttpException\n     */\n    public function getTicket(): string\n    {\n        $key = $this->getKey();\n        $ticket = $this->cache->get($key);\n\n        if ($ticket && is_string($ticket)) {\n            return $ticket;\n        }\n\n        $response = $this->httpClient->request('GET', '/cgi-bin/get_jsapi_ticket')->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($key, $response['ticket'], intval($response['expires_in']));\n\n        return $response['ticket'];\n    }\n\n    public function setKey(string $key): static\n    {\n        $this->key = $key;\n\n        return $this;\n    }\n\n    public function getKey(): string\n    {\n        return $this->key ?? $this->key = sprintf('open_work.jsapi_ticket.%s', $this->corpId);\n    }","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/OpenWork/JsApiTicket.php#L53-L89","documentation":"OpenWork\\JsApiTicket::getTicket() serves the corp-level JS-SDK ticket from cache; on miss it GETs /cgi-bin/get_jsapi_ticket through the authorizer-aware HTTP client and throws HttpException (raw JSON embedded) when the response has no ticket. Like all ticket calls it rides on the authorizer access token, so credential-chain problems surface here even though the ticket endpoint itself is trivial.","triggerScenarios":"Building wx.config signatures while the authorizer access token is invalid (authorization revoked, token expired and refresh failing downstream); the suite/authorizer credential chain broken; the corp restricted from JS-API usage.","commonSituations":"The authorizer uninstalled the suite app; signature pages breaking in bulk after an authorization change; cache wiped so tickets and tokens are re-fetched at once and the underlying token fetch fails first here.","solutions":["Decode the embedded errcode — 40001-class codes point at the credential chain, not the ticket API","Verify the authorizer still has the app installed and re-run the install flow if not","Refresh authorizer/suite tokens and clear the ticket cache, then retry","Confirm the corp/app still holds JS-API permission and is not frozen"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    $ticket = $jsApiTicket->getTicket();\n} catch (\\EasyWeChat\\Kernel\\Exceptions\\HttpException $e) {\n    $payload = json_decode(strstr($e->getMessage(), '{') ?: '[]', true) ?: [];\n    if (($payload['errcode'] ?? null) === 40001) {\n        // credential chain broken: refresh authorizer/suite tokens, clear ticket cache, retry once\n    }\n    report($e);\n}","preventionTips":["Watch this endpoint as a canary: it usually exposes authorizer-token breakage first","Clear ticket cache alongside token cache whenever credentials change","Disable JS-SDK pages for corps whose authorization is flagged revoked"],"tags":["php","easywechat","wechat-work","open-work","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-21T11:28:35.574Z"}