{"record":{"id":"851318b2881fcfbd","repo":"justauth/JustAuth","slug":"errmsg","errorCode":null,"errorMessage":"${errmsg}","messagePattern":"\\$\\{errmsg\\}","errorType":"exception","errorClass":"AuthException","httpStatus":null,"severity":"error","filePath":"src/main/java/me/zhyd/oauth/request/AbstractAuthDingtalkRequest.java","lineNumber":49,"sourceCode":"\n    public AbstractAuthDingtalkRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {\n        super(config, source, authStateCache);\n    }\n\n    @Override\n    public AuthToken getAccessToken(AuthCallback authCallback) {\n        return AuthToken.builder().accessCode(authCallback.getCode()).build();\n    }\n\n    @Override\n    public AuthUser getUserInfo(AuthToken authToken) {\n        String code = authToken.getAccessCode();\n        JSONObject param = new JSONObject();\n        param.put(\"tmp_auth_code\", code);\n        String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), param.toJSONString()).getBody();\n        JSONObject object = JSON.parseObject(response);\n        if (object.getIntValue(\"errcode\") != 0) {\n            throw new AuthException(object.getString(\"errmsg\"));\n        }\n        object = object.getJSONObject(\"user_info\");\n        AuthToken token = AuthToken.builder()\n            .openId(object.getString(\"openid\"))\n            .unionId(object.getString(\"unionid\"))\n            .build();\n        return AuthUser.builder()\n            .rawUserInfo(object)\n            .uuid(object.getString(\"unionid\"))\n            .nickname(object.getString(\"nick\"))\n            .username(object.getString(\"nick\"))\n            .gender(AuthUserGender.UNKNOWN)\n            .source(source.toString())\n            .token(token)\n            .build();\n    }\n\n    /**","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/justauth/JustAuth/blob/694bbf1b010d93404e3bfb4824d90e9ddfaebebb/src/main/java/me/zhyd/oauth/request/AbstractAuthDingtalkRequest.java#L31-L67","documentation":"AbstractAuthDingtalkRequest.getUserInfo posts the tmp_auth_code to https://oapi.dingtalk.com/sns/getuserinfo_bycode and checks the errcode field. Any non-zero errcode (plus errmsg) is rethrown as an AuthException carrying DingTalk's own message. Common codes: invalid/expired tmp_auth_code, signature problems, or wrong appId/appSecret on the qs/sns side.","triggerScenarios":"Calling login() or getUserInfo() where the code is stale (tmp_auth_code is single-use and short-lived), was already consumed, or the DingTalk app credentials are wrong; clock skew or network proxies mangling the POST body.","commonSituations":"User sits on the callback page before the server processes it and the code expires; retrying the callback (idempotency issue) reuses a consumed code; wrong appId/secret configured for the scan-login app; DingTalk API changes to getuserinfo_bycode (which historically required a signature).","solutions":["Exchange the tmp_auth_code immediately upon callback — it is one-time and expires within minutes; do not retry with the same code.","Verify the DingTalk scan-login app's appId/appSecret in AuthConfig match the app created in the DingTalk open platform.","Log the raw response before parsing to capture the exact errcode; handle errcode by re-prompting the QR scan when the code is invalid.","If the message mentions signature, prefer the DingTalk-signed request variants (AuthDingTalkRequest with sdk-based signing) instead of the raw POST."],"exampleFix":"// before\n// callback endpoint retries on failure with the same code -> errmsg 'code been used'\n\n// after\n// process the callback exactly once, store the result, and on AuthException re-run the QR flow:\ntry { return request.login(callback); }\ncatch (AuthException e) { log.warn(\"dingtalk login failed: {}\", e.getMessage()); return restartScanLogin(); }","handlingStrategy":"try-catch","validationCode":"if (StringUtils.isEmpty(callback.getCode())) { throw new IllegalArgumentException(\"DingTalk callback missing code\"); }","typeGuard":null,"tryCatchPattern":"try { return request.login(callback); } catch (AuthException e) { log.warn(\"DingTalk userinfo errcode: {}\", e.getMessage()); return restartQrLogin(); }","preventionTips":["Exchange the DingTalk tmp_auth_code exactly once, immediately on callback.","Store the login result keyed by code so retries do not re-consume it.","Verify scan-login appId/secret match the DingTalk open platform app.","Log the raw DingTalk response for errcode diagnosis."],"tags":["justauth","dingtalk","api-error","expired-code","external-api"],"backgroundTag":null,"analyzedSha":"694bbf1b010d93404e3bfb4824d90e9ddfaebebb","analyzedAt":"2026-08-14T15:16:59.945Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}