{"record":{"id":"7c71d958a17a2ee8","repo":"Tencent/APIJSON","slug":"key-0","errorCode":null,"errorMessage":"{} 内截至 {}:{} 时数组对象 key[]:{} 的数量达到 {} 已超限，必须在 0-{} 内 !","messagePattern":"(.+?) 内截至 (.+?):(.+?) 时数组对象 key\\[\\]:(.+?) 的数量达到 (.+?) 已超限，必须在 0-(.+?) 内 !","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java","lineNumber":612,"sourceCode":"\t@Override\n\tpublic Object onChildParse(int index, String key, M value, Object cache) throws Exception {\n\t\tboolean isFirst = index <= 0;\n\t\tboolean isMain = isFirst && type == TYPE_ITEM;\n\n\t\tObject child;\n\t\tboolean isEmpty;\n\n\t\tif (JSONMap.isArrayKey(key)) { // APIJSON Array\n\t\t\tif (isMain) {\n\t\t\t\tthrow new IllegalArgumentException(parentPath + \"/\" + key + \":{} 不合法！\"\n\t\t\t\t\t\t+ \"数组 []:{} 中第一个 key:{} 必须是主表 TableKey:{} ！不能为 arrayKey[]:{} ！\");\n\t\t\t}\n\n\t\t\tif (arrayConfig == null || arrayConfig.getPosition() == 0) {\n\t\t\t\tarrayCount ++;\n\t\t\t\tint maxArrayCount = parser.getMaxArrayCount();\n\t\t\t\tif (arrayCount > maxArrayCount) {\n\t\t\t\t\tthrow new IllegalArgumentException(path + \" 内截至 \" + key + \":{} 时数组对象 key[]:{} \"\n                            + \"的数量达到 \" + arrayCount + \" 已超限，必须在 0-\" + maxArrayCount + \" 内 !\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tString query = getString(value, KEY_QUERY);\n\t\t\tchild = parser.onArrayParse(value, path, key, isSubquery, cache instanceof List<?> ? (L) cache : null);\n\t\t\tisEmpty = child == null || ((List<?>) child).isEmpty();\n\n\t\t\tif (\"2\".equals(query) || \"ALL\".equals(query)) { // 不判断 isEmpty，因为分页数据可能只是某页没有\n\t\t\t\tString totalKey = JSONResponse.formatArrayKey(key) + \"Total\";\n\t\t\t\tString infoKey = JSONResponse.formatArrayKey(key) + \"Info\";\n\t\t\t\tif ((request.containsKey(totalKey) || request.containsKey(infoKey)\n\t\t\t\t\t\t|| request.containsKey(totalKey + \"@\") || request.containsKey(infoKey + \"@\")) == false) {\n\t\t\t\t\t// onParse(\"total@\", \"/\" + key + \"/total\");\n\t\t\t\t\t// onParse(infoKey + \"@\", \"/\" + key + \"/info\");\n\t\t\t\t\t// 替换为以下性能更好、对流程干扰最小的方式：\n\n\t\t\t\t\tString keyPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, \"/\" + key);","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L594-L630","documentation":"A DoS guard: each object parser counts array-key occurrences ('key[]:{}') and compares against parser.getMaxArrayCount(), whose default is AbstractParser.MAX_ARRAY_COUNT = 5. When the count of array objects exceeds the limit, parsing aborts with this message showing the current count and the max. Note the counter only increments when arrayConfig == null or position == 0, so nested array items don't double count.","triggerScenarios":"A single request object containing 6+ distinct 'xxx[]' keys (e.g. six parallel lists), reaching the 6th array key and exceeding the default max of 5.","commonSituations":"Dashboard/aggregate endpoints fetching many lists in one request; decreasing limits in a shared parser; combining several previously separate list requests into one batch call.","solutions":["Split the request into multiple API calls so each stays within the array-count limit.","Raise the limit server-side if legitimate: override getMaxArrayCount() in your AbstractParser subclass (or set AbstractParser.MAX_ARRAY_COUNT) — weigh the query-explosion risk first.","Prefer one array with joins/associations instead of many parallel arrays."],"exampleFix":"// before\n{ \"a[]\": {...}, \"b[]\": {...}, \"c[]\": {...}, \"d[]\": {...}, \"e[]\": {...}, \"f[]\": {...} }\n// after\n// request 1: a[],b[],c[] ; request 2: d[],e[],f[]","handlingStrategy":"validation","validationCode":"int arrays = 0;\nfor (String k : request.keySet()) if (k.endsWith(\"[]\")) arrays++;\nint max = 5; // mirror parser.getMaxArrayCount()\nif (arrays > max) throw new IllegalArgumentException(\"too many arrays (\" + arrays + \" > \" + max + \"), split the request\");","typeGuard":"function withinArrayLimit(obj: Record<string, unknown>, max = 5): boolean {\n  return Object.keys(obj).filter(k => k.endsWith('[]')).length <= max;\n}","tryCatchPattern":null,"preventionTips":["Count 'key[]' entries before sending; split requests over the limit.","Know your server's getMaxArrayCount() (default 5) and mirror it client-side.","Prefer joins/associations over many parallel arrays."],"tags":["apijson","array","limit","dos-guard","configuration"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}