{"record":{"id":"9983eb6d6e2f404c","repo":"Tencent/APIJSON","slug":"error-9983eb","errorCode":null,"errorMessage":"角色 {} 不存在！只能是[{}]中的一种！","messagePattern":"角色 (.+?) 不存在！只能是\\[(.+?)\\]中的一种！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java","lineNumber":277,"sourceCode":"\tpublic boolean verifyAccess(SQLConfig<T, M, L> config) throws Exception {\n\t\tif (ENABLE_VERIFY_ROLE == false) {\n\t\t\tthrow new UnsupportedOperationException(\"AbstractVerifier.ENABLE_VERIFY_ROLE == false \" +\n                    \"时不支持校验角色权限！如需支持则设置 AbstractVerifier.ENABLE_VERIFY_ROLE = true ！\");\n\t\t}\n\n\t\tString table = config == null ? null : config.getTable();\n\t\tif (table == null) {\n\t\t\treturn true;\n\t\t}\n\n\t\tString role = config.getRole();\n\t\tif (role == null) {\n\t\t\trole = UNKNOWN;\n\t\t}\n\t\telse {\n\t\t\tif (ROLE_MAP.containsKey(role) == false) {\n\t\t\t\tSet<String> NAMES = ROLE_MAP.keySet();\n\t\t\t\tthrow new IllegalArgumentException(\"角色 \" + role + \" 不存在！\" +\n                        \"只能是[\" + StringUtil.get(NAMES.toArray()) + \"]中的一种！\");\n\t\t\t}\n\n\t\t\tif (role.equals(UNKNOWN) == false) { //未登录的角色\n\t\t\t\tverifyLogin();\n\t\t\t}\n\t\t}\n\n\t\tRequestMethod method = config.getMethod();\n\t\tverifyRole(config, table, method, role);\n\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void verifyRole(SQLConfig<T, M, L> config, String table, RequestMethod method, String role) throws Exception {\n\t\tverifyAllowRole(config, table, method, role); //验证允许的角色\n\t\tverifyUseRole(config, table, method, role); //验证使用的角色","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java#L259-L295","documentation":"Inside verifyAccess(), after the table is resolved, the role string taken from config.getRole() must exist in the static ROLE_MAP. ROLE_MAP holds the well-known APIJSON roles (ADMIN, OWNER, CONTACT, MEMBER, CIRCLE, UNKNOWN and friends); an unrecognized name throws IllegalArgumentException together with the list of legal names. This is a request-contract error: the client sent a role APIJSON cannot map.","triggerScenarios":"A request object carries \"role\":\"SUPERUSER\" (or a typo like \"ownner\", or a localized/empty-string role) and the request reaches verifyAccess; ROLE_MAP.containsKey(role) is false and the exception lists the allowed role names.","commonSituations":"Client and server disagree on the role vocabulary; front-end sends an application-specific role that was never registered; case mismatch (\"owner\" vs \"OWNER\"); migrating from an older APIJSON whose role list differed.","solutions":["Change the request to use one of the roles printed in the message (they come from ROLE_MAP.keySet(), e.g. ADMIN, OWNER, CONTACT, CIRCLE, MEMBER, UNKNOWN).","Check for case/spelling typos in the \"role\" value in the request JSON — matching is exact and case-sensitive.","If a custom role is genuinely needed, extend the verifier and populate ROLE_MAP (or override verifyAccess/verifyRole) in your subclass instead of sending an unregistered name.","Omit the role key entirely to fall back to UNKNOWN/anonymous handling when that is the intent."],"exampleFix":"// before\n{\n  \"User\": { \"id\": 1 },\n  \"role\": \"superuser\",\n  \"tag\": \"User\"\n}\n\n// after\n{\n  \"User\": { \"id\": 1 },\n  \"role\": \"OWNER\",\n  \"tag\": \"User\"\n}","handlingStrategy":"validation","validationCode":"Set<String> allowed = AbstractVerifier.ROLE_MAP.keySet();\nif (role != null && !allowed.contains(role)) {\n    throw new ClientError(\"role must be one of \" + allowed + \", got \" + role);\n}","typeGuard":"boolean isValidRole(String r) { return r == null || AbstractVerifier.ROLE_MAP.containsKey(r); }","tryCatchPattern":"catch (IllegalArgumentException e) when message starts with \"角色\" -> map to HTTP 400 with the allowed-role list from ROLE_MAP.keySet().","preventionTips":["Expose the role list from ROLE_MAP to clients via a metadata endpoint or generated constants.","Never invent client-side role names; share an enum of roles across front-end and backend."],"tags":["apijson","validation","roles","request-contract"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}