{"record":{"id":"dd8f4f2f0f3a6230","repo":"Tencent/APIJSON","slug":"version-version-method-method-name","errorCode":null,"errorMessage":"找不到 version: ${version}, method: ${method.name()}, tag: ${tag} 对应的 structure ！非开放请求必须是后端 Request 表中校验规则允许的操作！\n ${error}\n如果需要则在 Request 表中新增配置！","messagePattern":"找不到 version: (.+?), method: (.+?), tag: (.+?) 对应的 structure ！非开放请求必须是后端 Request 表中校验规则允许的操作！\n (.+?)\n如果需要则在 Request 表中新增配置！","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractParser.java","lineNumber":2288,"sourceCode":"\t\tString _method = key == null ? null : getString(request, KEY_METHOD);\n\t\tif (_method != null) {\n\t\t\tRequestMethod method = RequestMethod.valueOf(_method); // 必须精准匹配，避免缓存命中率低\n\t\t\tthis.setMethod(method);\n\t\t\top.setMethod(method);\n\t\t}\n\t}\n\n\tprotected M getRequestStructure(RequestMethod method, String tag, int version) throws Exception {\n\t\t// 获取指定的JSON结构 <<<<<<<<<<<<\n\t\tM object = null;\n\t\tString error = \"\";\n\t\ttry {\n\t\t\tobject = getStructure(\"Request\", method.name(), tag, version);\n\t\t} catch (Exception e) {\n\t\t\terror = e.getMessage();\n\t\t}\n\t\tif (object == null) { // empty表示随意操作 || object.isEmpty()) {\n\t\t\tthrow new UnsupportedOperationException(\"找不到 version: \" + version + \", method: \" + method.name() + \", tag: \" + tag + \" 对应的 structure ！\" + \"非开放请求必须是后端 Request 表中校验规则允许的操作！\\n \" + error + \"\\n如果需要则在 Request 表中新增配置！\");\n\t\t}\n\n\t\treturn object;\n\t}\n\n\tpublic static final Map<String, RequestMethod> KEY_METHOD_ENUM_MAP;\n\tstatic {\n\t\tKEY_METHOD_ENUM_MAP = new LinkedHashMap<>();\n\t\tKEY_METHOD_ENUM_MAP.put(KEY_GET, RequestMethod.GET);\n\t\tKEY_METHOD_ENUM_MAP.put(KEY_GETS, RequestMethod.GETS);\n\t\tKEY_METHOD_ENUM_MAP.put(KEY_HEAD, RequestMethod.HEAD);\n\t\tKEY_METHOD_ENUM_MAP.put(KEY_HEADS, RequestMethod.HEADS);\n\t\tKEY_METHOD_ENUM_MAP.put(KEY_POST, RequestMethod.POST);\n\t\tKEY_METHOD_ENUM_MAP.put(KEY_PUT, RequestMethod.PUT);\n\t\tKEY_METHOD_ENUM_MAP.put(KEY_DELETE, RequestMethod.DELETE);\n\t}\n\n\tprivate void parseMethodDirective(String key, RequestMethod keyMethod, @NotNull M request) throws Exception {","sourceCodeStart":2270,"sourceCodeEnd":2306,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java#L2270-L2306","documentation":"For non-open requests (anything requiring structure validation), the parser looks up the JSON structure for the given version/method/tag in the backend 'Request' table via getStructure(...). If nothing is found, an UnsupportedOperationException is thrown: the operation is not permitted unless a matching Request-table entry whitelists it.","triggerScenarios":"A POST/PUT request with tag 'User' when the Request table has no row for method POST + tag User + current version; using GETS/HEADS (non-open variants) with an unregistered tag; version mismatch (client sends version 3, table only has version <= 2 config).","commonSituations":"New table/operation added without inserting the Request-table permission config; tag typo or wrong case; METHOD directive key ('INSERT', 'UPDATE'...) differing from the tag registered; version bump on client before backend config updated; demo/backend init script not run so the Request table is empty.","solutions":["Add a Request-table row matching method + tag + version that prescribes the allowed structure","Verify tag spelling/case and the method actually mapped (e.g. POST with 'INSERT': 'User' maps to method POST, tag User)","Align request 'version' with the max version present in the Request table (or add config for the new version)","If the operation should be open, use the open endpoints/keys instead of the non-open method"],"exampleFix":"-- before: no row\n-- after: INSERT INTO Request (version, method, tag, structure, detail) VALUES (1, 'POST', 'User', '{ \"INSERT\": { \"User\": { \"INSERT\": ... } } }', 'allow add user');","handlingStrategy":"try-catch","validationCode":"// Before allowing a tag through, check it is registered (requires access to the Request table, e.g. via a HEADS/GUESTS probe or cached config)\nasync function assertTagRegistered(api, method, tag, version) {\n  const cfg = await api.queryRequestTable(method, tag, version); // your admin endpoint or cached copy\n  if (cfg == null) throw new Error(`tag '${tag}' for ${method} v${version} is not registered in Request table`);\n}","typeGuard":null,"tryCatchPattern":"try { client.post(path, request); } catch (UnsupportedOperationException e) { if (e.getMessage().contains('对应的 structure')) { /* surface 'operation not permitted, contact admin' instead of a stack trace */ } else throw e; }","preventionTips":["Add the Request-table (method, tag, version) row in the same migration/PR that introduces a new table or operation","Automate a startup check that every tag your client can send exists in Request for the shipped version","Keep client version and Request-table max version in lockstep during releases"],"tags":["apijson","request-table","permission","configuration"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}