{"record":{"id":"c8196a72f69b8c0d","repo":"justauth/JustAuth","slug":"errmsg-c8196a","errorCode":null,"errorMessage":"${errmsg}","messagePattern":"\\$\\{errmsg\\}","errorType":"exception","errorClass":"AuthException","httpStatus":null,"severity":"error","filePath":"src/main/java/me/zhyd/oauth/request/AuthWeChatEnterpriseThirdQrcodeRequest.java","lineNumber":118,"sourceCode":"    @Override\n    protected String doGetUserInfo(AuthToken authToken) {\n        JSONObject data = new JSONObject();\n        data.put(\"auth_code\", authToken.getCode());\n        return new HttpUtils(config.getHttpConfig())\n            .post(userInfoUrl(authToken), data.toJSONString()).getBody();\n    }\n\n    @Override\n    protected String userInfoUrl(AuthToken authToken) {\n        return UrlBuilder.fromBaseUrl(source.userInfo())\n            .queryParam(\"access_token\", authToken.getAccessToken()).\n                build();\n    }\n\n    private JSONObject checkResponse(String response) {\n        JSONObject object = JSONObject.parseObject(response);\n        if (object.containsKey(\"errcode\") && object.getIntValue(\"errcode\") != 0) {\n            throw new AuthException(object.getString(\"errmsg\"), source);\n        }\n        return object;\n    }\n}\n","sourceCodeStart":100,"sourceCodeEnd":123,"githubUrl":"https://github.com/justauth/JustAuth/blob/694bbf1b010d93404e3bfb4824d90e9ddfaebebb/src/main/java/me/zhyd/oauth/request/AuthWeChatEnterpriseThirdQrcodeRequest.java#L100-L123","documentation":"AuthWeChatEnterpriseThirdQrcodeRequest.checkResponse(String) parses the raw HTTP body and throws AuthException(errmsg, source) when the JSON contains `errcode` with a non-zero value. This is the standard WeChat Work error envelope; the exception carries the provider source for context but no numeric code — only the Chinese/English errmsg string from the server.","triggerScenarios":"WeChat Work API calls in the third-party QR flow returning errcode != 0: getuserinfo with an expired provider_access_token (40058/42001), getuserdetail without the required read permission (48011/60011), or invalid code passed from the QR callback.","commonSituations":"provider_access_token cached too long and expired (2h validity); the service provider app lacks '获取成员详细信息' (read-sensitive/user-detail) permission so getuserdetail fails; user belongs to a different enterprise than the authorized one; clock or encoding issues corrupting the code parameter.","solutions":["Read the errmsg and cross-reference the errcode table in WeChat Work docs (the number is in the response even though the exception only carries the text).","For 42001/40014 (token expired): invalidate the cached provider_access_token and re-fetch via getAccessToken before retrying.","For 48011/60011 (permission): apply for member-detail read permission on the service-provider app and re-publish.","Log the raw response body alongside the exception to always retain the numeric errcode."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// check provider token age before user-info calls\nlong age = System.currentTimeMillis() - providerTokenFetchedAt;\nif (age > 90 * 60 * 1000L) { // refresh well before 2h expiry\n    providerToken = thirdQrcodeRequest.getAccessToken(dummyCallback);\n}","typeGuard":null,"tryCatchPattern":"try {\n    return request.getUserInfo(token);\n} catch (AuthException e) {\n    String m = String.valueOf(e.getMessage());\n    if (m.contains(\"access_token\" ) || m.contains(\"42001\") || m.contains(\"40014\")) {\n        providerToken = fetchNewProviderToken(); // invalidate + refetch, then retry once\n        return request.getUserInfo(withToken(providerToken));\n    }\n    throw e;\n}","preventionTips":["Log raw WeChat Work response bodies to retain errcode numbers.","Apply for member-detail read permission before shipping the login flow.","Retry once on token-expiry errors, never on permission errors."],"tags":["justauth","wechat-work","api-error","errcode","token-expiry"],"backgroundTag":null,"analyzedSha":"694bbf1b010d93404e3bfb4824d90e9ddfaebebb","analyzedAt":"2026-08-14T15:16:59.945Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}