{"record":{"id":"8a503375dd134720","repo":"dromara/Sa-Token","slug":"30105-8a5033","errorCode":"30105","errorMessage":"无效 client_id: ","messagePattern":"无效 client_id: ","errorType":"exception","errorClass":"SaOAuth2ClientModelException","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java","lineNumber":61,"sourceCode":"\t/**\n\t * 获取 ClientModel，根据 clientId\n\t *\n\t * @param clientId /\n\t * @return /\n\t */\n\tpublic SaClientModel getClientModel(String clientId) {\n\t\treturn SaOAuth2Manager.getDataLoader().getClientModel(clientId);\n\t}\n\n\t/**\n\t * 校验 clientId 信息并返回 ClientModel，如果找不到对应 Client 信息则抛出异常\n\t * @param clientId /\n\t * @return /\n\t */\n\tpublic SaClientModel checkClientModel(String clientId) {\n\t\tSaClientModel clientModel = getClientModel(clientId);\n\t\tif(clientModel == null) {\n\t\t\tthrow new SaOAuth2ClientModelException(\"无效 client_id: \" + clientId)\n\t\t\t\t\t.setClientId(clientId)\n\t\t\t\t\t.setCode(SaOAuth2ErrorCode.CODE_30105);\n\t\t}\n\t\treturn clientModel;\n\t}\n\n\t/**\n\t * 校验：clientId 与 clientSecret 是否正确，正确返回 SaClientModel，不正确抛出异常\n\t * @param clientId 应用id\n\t * @param clientSecret 秘钥\n\t * @return SaClientModel对象\n\t */\n\tpublic SaClientModel checkClientSecret(String clientId, String clientSecret) {\n\t\tSaClientModel cm = checkClientModel(clientId);\n\t\tif(cm.clientSecret == null || ! cm.clientSecret.equals(clientSecret)) {\n\t\t\tthrow new SaOAuth2ClientModelException(\"无效 client_secret: \" + clientSecret)\n\t\t\t\t\t.setClientId(clientId)\n\t\t\t\t\t.setCode(SaOAuth2ErrorCode.CODE_30115);","sourceCodeStart":43,"sourceCodeEnd":79,"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#L43-L79","documentation":"Thrown by SaOAuth2Template.checkClientModel: no SaClientModel exists for the given client_id (the data loader returned null). This is the primary 'unknown client' error for every OAuth2 endpoint that validates a client. It is thrown as SaOAuth2ClientModelException carrying the clientId. Error code 30105.","triggerScenarios":"Any authorize/token request with an unregistered client_id; client_id correct in one environment but the service points at another data loader/redis DB; client registration written to a store the oauth2-server does not read.","commonSituations":"Test vs production client registries differ; SaClientModel list configured in application.yml but a custom data loader overrides it and returns null; typo in client_id; registration lost after cache/redis flush.","solutions":["Verify the client_id exists in the active registration source (SaOAuth2DataLoader / configured client list / redis)","Confirm environment alignment: the service the client calls is the one where the client is registered","Implement/verify SaOAuth2DataLoader.getClientModel returns a SaClientModel for that exact id"],"exampleFix":"// before\n@Override\npublic SaClientModel getClientModel(String clientId) {\n    return null; // never registered\n}\n\n// after\n@Override\npublic SaClientModel getClientModel(String clientId) {\n    return clients.get(clientId); // pre-loaded map: \"1001\" -> SaClientModel\n}","handlingStrategy":"try-catch","validationCode":"if(SaOAuth2Manager.getDataLoader().getClientModel(clientId) == null) {\n    throw new IllegalArgumentException(\"unknown client_id: \" + clientId);\n}","typeGuard":null,"tryCatchPattern":"catch(SaOAuth2ClientModelException e) {\n    if(\"30105\".equals(e.getCode())) return 400 \"unknown client_id\"; // e.getClientId() available\n}","preventionTips":["Seed client registrations in a startup runner and fail fast if a required client is missing","Use environment-specific client registries checked into the repo to avoid drift"],"tags":["oauth2","client-id","registration","sa-token"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}