{"record":{"id":"910996c9b83743b0","repo":"w7corp/easywechat","slug":"no-component-verify-ticket-found","errorCode":null,"errorMessage":"No component_verify_ticket found.","messagePattern":"No component_verify_ticket found\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/OpenPlatform/VerifyTicket.php","lineNumber":55,"sourceCode":"        return $this;\n    }\n\n    public function setTicket(string $ticket): static\n    {\n        $this->cache->set($this->getKey(), $ticket, 6000);\n\n        return $this;\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function getTicket(): string\n    {\n        $ticket = $this->cache->get($this->getKey());\n\n        if (! $ticket || ! is_string($ticket)) {\n            throw new RuntimeException('No component_verify_ticket found.');\n        }\n\n        return $ticket;\n    }\n}\n","sourceCodeStart":37,"sourceCodeEnd":61,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/OpenPlatform/VerifyTicket.php#L37-L61","documentation":"OpenPlatform\\VerifyTicket::getTicket() only reads the shared cache for the component_verify_ticket that WeChat pushes roughly every 10 minutes to the component's auth-event (授权事件接收) endpoint — there is no HTTP fetch here. RuntimeException means the cache has no usable string ticket yet. All component-access-token flows (pre-auth codes, token refresh) fail fast until a push has been received and stored.","triggerScenarios":"Calling createPreAuthorizationCode() or any component-token flow before the first push arrived; the receiving endpoint is not routed to the open-platform Server so pushes never reach the cache; the cache is not shared (file cache across containers) between receiver and consumers; cache recently wiped.","commonSituations":"Fresh open-platform deployment still waiting for the first push; the 授权事件接收URL is 404/behind auth; Redis switched or its prefix changed after a deploy; load-balanced workers each using local disk caches.","solutions":["Point the component's 授权事件接收URL at a public route that runs $openPlatform->getServer()->serve() so ticket pushes get captured into the cache","Use one shared cache backend (Redis) with the same prefix for both the receiver and all consumers","After a first deploy or cache wipe, wait for the next push (up to ~10 minutes) before retrying","Log one push arrival to confirm the endpoint works, then monitor it"],"exampleFix":"// before: workers use a cache that never received the push\n$code = $openPlatform->createPreAuthorizationCode(); // RuntimeException\n\n// after: receiver route and workers share the same Redis-backed cache\n// route: POST /open-platform/notify → $openPlatform->getServer()->serve();\n$openPlatform->setCache(new \\Symfony\\Component\\Cache\\Adapter\\RedisAdapter($redis, 'easywechat'));","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    $ticket = $openPlatform->getVerifyTicket()->getTicket();\n} catch (\\RuntimeException $e) {\n    // pushes not arriving yet: back off and retry later; alert if this persists past ~20 minutes\n    report($e);\n    return retry_after(600);\n}","preventionTips":["Health-check the 授权事件接收 endpoint externally so missed ticket pushes surface quickly","Never use per-instance file caches for open-platform state","After rotating cache backends or prefixes, expect one push cycle (~10 min) of warm-up","Alert when the cached ticket's age exceeds ~20 minutes"],"tags":["php","easywechat","wechat","open-platform","verify-ticket","cache","webhook"],"backgroundTag":"missing-webhook-pushed-credential","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}