{"record":{"id":"6ce167ff77de42f1","repo":"Tencent/APIJSON","slug":"method-name-field-must","errorCode":null,"errorMessage":"{method}请求，{name} 里面不能缺少 {field} 等[{must}]内的任何字段！","messagePattern":"(.+?)请求，(.+?) 里面不能缺少 (.+?) 等\\[(.+?)\\]内的任何字段！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java","lineNumber":976,"sourceCode":"//\t\tObject code = target.get(CODE.name());\n\n\t\t// 移除字段<<<<<<<<<<<<<<<<<<<\n\t\tString[] removes = StringUtil.split(remove);\n\t\tif (removes != null && removes.length > 0) {\n\t\t\tfor (String r : removes) {\n\t\t\t\treal.remove(r);\n\t\t\t}\n\t\t}\n\t\t// 移除字段>>>>>>>>>>>>>>>>>>>\n\n\t\t// 判断必要字段是否都有<<<<<<<<<<<<<<<<<<<\n\t\tString[] musts = StringUtil.split(must);\n\t\tSet<String> mustSet = new HashSet<String>();\n\n\t\tif (musts != null && musts.length > 0) {\n\t\t\tfor (String s : musts) {\n\t\t\t\tif (real.get(s) == null && real.get(s+\"@\") == null) {  // 可能传null进来，这里还会通过 real.containsKey(s) == false) {\n\t\t\t\t\tthrow new IllegalArgumentException(method + \"请求，\"\n                            + name + \" 里面不能缺少 \" + s + \" 等[\" + must + \"]内的任何字段！\");\n\t\t\t\t}\n\n\t\t\t\tmustSet.add(s);\n\t\t\t}\n\t\t}\n\t\t// 判断必要字段是否都有>>>>>>>>>>>>>>>>>>>\n\n\t\tString[] sks = StringUtil.split(getString(real, KEY_STRING));\n\t\tString[] trims = StringUtil.split(getString(real, KEY_TRIM));\n\t\tList<String> stringKeyList = sks == null || sks.length <= 0 ? null : Arrays.asList(sks);\n\t\tList<String> trimKeyList = trims == null || trims.length <= 0 ? null : Arrays.asList(trims);\n\n\t\tSet<String> objKeySet = new HashSet<String>(); // 不能用tableKeySet，仅判断 Table:{} 会导致 key:{ Table:{} } 绕过判断\n\n\t\t// 解析内容<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n\t\tSet<Map.Entry<String, Object>> set = new LinkedHashSet<>(target.entrySet());","sourceCodeStart":958,"sourceCodeEnd":994,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java#L958-L994","documentation":"Thrown while merging a request with its Request-table template: a field listed in the MUST list is absent from the client's object (neither field nor field@ reference is present). MUST is the required-fields contract for the request.","triggerScenarios":"Request table row for e.g. POST User has MUST=\"name,pictureUrl\" but the client posts {\"User\":{\"name\":\"a\"}} — pictureUrl (and pictureUrl@) missing.","commonSituations":"New required field added to MUST after clients shipped; frontend conditionally omits optional-looking fields; typo between the MUST entry and the key the client actually sends; field renamed in an API version bump.","solutions":["Add every MUST-listed field to the request body (or a field@ reference like \"pictureUrl@\":\"/User/avatar\")","If the field is genuinely optional, remove it from MUST in the Request table","Check for typos/case mismatch between MUST entries and sent keys"],"exampleFix":"// before\n{\"User\":{\"name\":\"a\"}}  // MUST=\"name,pictureUrl\"\n// after\n{\"User\":{\"name\":\"a\",\"pictureUrl\":\"https://...\"}}","handlingStrategy":"validation","validationCode":"const MUST_FIELDS = ['name', 'pictureUrl']; // mirror of Request-table MUST\nfunction assertMust(obj, fields) {\n  for (const f of fields) {\n    if (obj[f] == null && obj[f + '@'] == null) throw new Error(`missing required field: ${f}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"catch (e) { if (/不能缺少/.test(e.message)) { const m = e.message.match(/缺少 (\\S+) 等\\[(.*?)\\]/); highlightMissingFields(m ? [m[1]] : parseList(m[2])); } else throw e; }","preventionTips":["Keep a client-side copy of MUST lists per endpoint and validate before send","When the backend adds a MUST field, version the client update together with it","Remember field@ references satisfy MUST too — use them for derived values"],"tags":["apijson","required-field","request-table","must"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}