{"record":{"id":"558905d36b79c625","repo":"dromara/Sa-Token","slug":"30110","errorCode":"30110","errorMessage":"无效 code: ","messagePattern":"无效 code: ","errorType":"exception","errorClass":"SaOAuth2AuthorizationCodeException","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java","lineNumber":396,"sourceCode":"\n\t/**\n\t * 获取 CodeModel，无效的 code 会返回 null\n\t * @param code /\n\t * @return /\n\t */\n\tpublic CodeModel getCode(String code) {\n\t\treturn SaOAuth2Manager.getDao().getCode(code);\n\t}\n\n\t/**\n\t * 校验 Code，成功返回 CodeModel，失败则抛出异常\n\t * @param code /\n\t * @return /\n\t */\n\tpublic CodeModel checkCode(String code) {\n\t\tCodeModel cm = SaOAuth2Manager.getDao().getCode(code);\n\t\tif(cm == null) {\n\t\t\tthrow new SaOAuth2AuthorizationCodeException(\"无效 code: \" + code)\n\t\t\t\t\t.setAuthorizationCode(code)\n\t\t\t\t\t.setCode(SaOAuth2ErrorCode.CODE_30110);\n\t\t}\n\t\treturn cm;\n\t}\n\n\t/**\n\t * 获取 Code，根据索引： clientId、loginId\n\t * @param clientId /\n\t * @param loginId /\n\t * @return /\n\t */\n\tpublic String getCodeValue(String clientId, Object loginId) {\n\t\treturn SaOAuth2Manager.getDao().getCodeValue(clientId, loginId);\n\t}\n\n\n\t// ----------------- Access-Token 相关 -----------------","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java#L378-L414","documentation":"Thrown by SaOAuth2Template.checkCode when the authorization code cannot be found in the DAO (code 30110, SaOAuth2AuthorizationCodeException). Codes are short-lived, single-use server-issued credentials; a miss means the code was never issued, already consumed, expired, or lost (e.g. different DAO/Redis node).","triggerScenarios":"Calling the token endpoint (/oauth2/token?grant_type=authorization_code) with a code that was already redeemed, has expired past its configured timeout, was truncated/URL-mangled, or when the server DAO was flushed/restarted with memory storage.","commonSituations":"Double submission of the token request (browser retry, duplicate HTTP call); front-end losing characters of the code due to missing URL encoding; dev server restart clearing in-memory code cache; multiple instances without shared Redis.","solutions":["Confirm the code is sent exactly as issued and URL-encoded in the token request","Redo the authorize flow to get a fresh code — codes are single-use and expire quickly (default ~5 min)","If running multiple OAuth2 server nodes, ensure they share the same Redis DAO so codes are visible cluster-wide"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if (SaFoxUtil.isEmpty(code)) throw new IllegalArgumentException(\"code is empty\");\nif (SaOAuth2Manager.getDao().getCode(code) == null) { /* code dead -> restart flow */ }","typeGuard":null,"tryCatchPattern":"try { return saOAuth2Template.checkCode(code); } catch (SaOAuth2AuthorizationCodeException e) { redirectUserToAuthorize(); // get fresh code\n return null; }","preventionTips":["Redeem the code exactly once, immediately after receiving it","Use a shared Redis DAO so codes survive restarts and are visible to all nodes"],"tags":["oauth2","authorization-code","token","validation"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}