{"record":{"id":"b8fdde1796b20197","repo":"w7corp/easywechat","slug":"getphonenumber-error-s","errorCode":null,"errorMessage":"getPhoneNumber error: %s","messagePattern":"getPhoneNumber error: (.+?)","errorType":"exception","errorClass":"HttpException","httpStatus":null,"severity":"error","filePath":"src/MiniApp/Utils.php","lineNumber":51,"sourceCode":"\n    public function decryptSession(string $sessionKey, string $iv, string $ciphertext): array\n    {\n        return Decryptor::decrypt($sessionKey, $iv, $ciphertext);\n    }\n\n    /**\n     * @throws HttpException\n     */\n    public function getPhoneNumber(string $code): array\n    {\n        $response = $this->app->createClient()->request('POST', '/wxa/business/getuserphonenumber', [\n            'json' => [\n                'code' => $code,\n            ],\n        ])->toArray(false);\n\n        if (isset($response['errcode']) && $response['errcode'] !== 0) {\n            throw new HttpException('getPhoneNumber error: '.json_encode($response, JSON_UNESCAPED_UNICODE));\n        }\n\n        if (empty($response['phone_info'])) {\n            throw new HttpException('getPhoneNumber error: '.json_encode($response, JSON_UNESCAPED_UNICODE));\n        }\n\n        return $response;\n    }\n}\n","sourceCodeStart":33,"sourceCodeEnd":61,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/MiniApp/Utils.php#L33-L61","documentation":"Thrown by MiniApp\\Utils::getPhoneNumber() when POST /wxa/business/getuserphonenumber returns a non-zero errcode. The raw WeChat response is JSON-encoded into the exception message, so the exact errcode/errmsg is always embedded. It means WeChat accepted the HTTP request but refused to release the phone number for the one-time code you supplied.","triggerScenarios":"Calling $utils->getPhoneNumber($code) with a code that is expired, already consumed (codes are single-use), truncated, or issued for a different appid; also when the mini program account is not eligible for the phone-number API (individual subject, not certified, or the paid phone-number service not enabled).","commonSituations":"Frontend caches or replays the code from the open-type=\"getPhoneNumber\" button across retries/debugging; a developer copies a logged request and re-runs it manually; the mini program is a personal (个人) subject or lacks certification; the 2023+ paid phone-number billing is not activated in the MP console.","solutions":["json_decode the tail of the exception message and branch on errcode/errmsg (40029 = invalid code, 45011 = rate limited, permission-class codes point to account eligibility)","Make the mini program request a brand-new code for every attempt and send it to the backend exactly once; never reuse a code across requests","Confirm the mini program is enterprise-certified and the phone-number capability is enabled (and paid where required) in the MP console","Verify the code was issued for the same appid the backend uses (no direct-vs-component mixups)"],"exampleFix":"// before: reusing a code captured earlier (single-use, short TTL)\n$code = $session->get('phone_code');\n$phone = $utils->getPhoneNumber($code);\n\n// after: always consume the code from this request, exactly once\n$code = (string) $request->input('code');\nif ($code === '') {\n    abort(422, 'phone code required');\n}\n$phone = $utils->getPhoneNumber($code);","handlingStrategy":"try-catch","validationCode":"if ($code === '' || strlen($code) > 64) {\n    throw new \\InvalidArgumentException('A fresh open-type=\"getPhoneNumber\" code is required.');\n}","typeGuard":null,"tryCatchPattern":"use EasyWeChat\\Kernel\\Exceptions\\HttpException;\n\ntry {\n    $phone = $utils->getPhoneNumber($code);\n} catch (HttpException $e) {\n    $payload = json_decode(strstr($e->getMessage(), '{') ?: '[]', true) ?: [];\n    if (($payload['errcode'] ?? null) === 40029) {\n        // code invalid/used: ask the mini program for a new one; do NOT retry the same code\n    }\n    report($e);\n}","preventionTips":["Treat phone codes as single-use and short-lived: request a new one for every attempt","Pass the code straight from the request payload; never store it in session or replay it from logs","Keep the mini program certified and the phone-number capability enabled in the MP console","Log the embedded errcode, not just the exception message"],"tags":["php","easywechat","wechat","miniapp","phone-number","http-error","one-time-code"],"backgroundTag":"one-time-code-exchange-failed","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}