{"record":{"id":"5df88e7419c4681d","repo":"dromara/Sa-Token","slug":"30101","errorCode":"30101","errorMessage":"client_id 不可为空","messagePattern":"client_id 不可为空","errorType":"validation","errorClass":"SaOAuth2Exception","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/request/RequestAuthModel.java","lineNumber":189,"sourceCode":"\t\treturn nonce;\n\t}\n\n\t/**\n\t * @param nonce 要设置的随机数\n\t * @return 对象自身\n\t */\n\tpublic RequestAuthModel setNonce(String nonce) {\n\t\tthis.nonce = nonce;\n\t\treturn this;\n\t}\n\n\t/**\n\t * 数据自检\n\t * @return 对象自身\n\t */\n\tpublic RequestAuthModel checkModel() {\n\t\tif(SaFoxUtil.isEmpty(clientId)) {\n\t\t\tthrow new SaOAuth2Exception(\"client_id 不可为空\").setCode(SaOAuth2ErrorCode.CODE_30101);\n\t\t}\n\t\tif(SaFoxUtil.isEmpty(scopes)) {\n\t\t\tthrow new SaOAuth2Exception(\"scope 不可为空\").setCode(SaOAuth2ErrorCode.CODE_30102);\n\t\t}\n\t\tif(SaFoxUtil.isEmpty(redirectUri)) {\n\t\t\tthrow new SaOAuth2Exception(\"redirect_uri 不可为空\").setCode(SaOAuth2ErrorCode.CODE_30103);\n\t\t}\n\t\tif(SaFoxUtil.isEmpty(String.valueOf(loginId))) {\n\t\t\tthrow new SaOAuth2Exception(\"LoginId 不可为空\").setCode(SaOAuth2ErrorCode.CODE_30104);\n\t\t}\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"RequestAuthModel{\" +\n\t\t\t\t\"clientId='\" + clientId + '\\'' +\n\t\t\t\t\", scopes=\" + scopes +","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/request/RequestAuthModel.java#L171-L207","documentation":"Thrown by RequestAuthModel.checkModel() when the clientId field is empty. The OAuth2 server builds a RequestAuthModel for every authorize/token flow and self-checks it before generating code or tokens; an empty client_id fails the first check. Error code 30101.","triggerScenarios":"Calling the /oauth2/authorize endpoint without a client_id request parameter, or programmatically building a RequestAuthModel and calling checkModel() without setClientId(). Also happens when a custom grant-type handler forgets to set ra.clientId before token generation.","commonSituations":"Misconfigured authorize URL in the client app, a typo in the parameter name (e.g. clientId instead of client_id), or a reverse proxy stripping query parameters.","solutions":["Ensure the authorize request includes a non-empty client_id parameter that matches a registered SaClientModel","If building RequestAuthModel manually, set ra.clientId (or call setClientId) before checkModel()/generateAccessToken()","Check the actual outgoing request URL/params (browser network tab or gateway logs) to confirm client_id is present"],"exampleFix":"// before\nhttp://host/oauth2/authorize?response_type=code&redirect_uri=...\n\n// after\nhttp://host/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=...","handlingStrategy":"validation","validationCode":"// before building/sending the authorize request\nif(SaFoxUtil.isEmpty(clientId)) {\n    throw new IllegalArgumentException(\"client_id is required\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    oauth2Template or processor call\n} catch(SaOAuth2Exception e) {\n    if(e.getCode().equals(\"30101\")) { /* return 400 with client_id hint */ }\n}","preventionTips":["Centralize authorize URL construction in one client-side helper that asserts client_id is set","Write an integration test for each configured client_id hitting /oauth2/authorize"],"tags":["oauth2","validation","client-id","sa-token"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}