{"record":{"id":"b3e9d212c020f3b8","repo":"Tencent/APIJSON","slug":"key-0-b3e9d2","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":650,"sourceCode":"\t\t\t\t\tString infoPath = keyPath + \"/info\";\n\t\t\t\t\tresponse.put(totalKey, onReferenceParse(totalPath));\n\t\t\t\t\tresponse.put(infoKey, onReferenceParse(infoPath));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse { //APIJSON Object\n\t\t\tboolean isTableKey = JSONMap.isTableKey(Pair.parseEntry(key, true).getKey());\n\t\t\tif (type == TYPE_ITEM && isTableKey == false) {\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 ( //避免使用 \"test\":{\"Test\":{}} 绕过限制，实现查询爆炸   isTableKey &&\n\t\t\t\t\t(arrayConfig == null || arrayConfig.getPosition() == 0)) {\n\t\t\t\tobjectCount ++;\n\t\t\t\tint maxObjectCount = parser.getMaxObjectCount();\n\t\t\t\tif (objectCount > maxObjectCount) {  //TODO 这里判断是批量新增/修改，然后上限为 maxUpdateCount\n\t\t\t\t\tthrow new IllegalArgumentException(path + \" 内截至 \" + key + \":{} 时对象\"\n\t\t\t\t\t\t\t+ \" key:{} 的数量达到 \" + objectCount + \" 已超限，必须在 0-\" + maxObjectCount + \" 内 !\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchild = parser.onObjectParse(value, path, key, isMain ? arrayConfig.setType(SQLConfig.TYPE_ITEM_CHILD_0) : null\n\t\t\t\t\t, isSubquery, cache instanceof Map<?, ?> ? (M) cache : null);\n\n\t\t\tisEmpty = child == null || ((Map<?, ?>) child).isEmpty();\n\t\t\tif (isFirst && isEmpty) {\n\t\t\t\tinvalidate();\n\t\t\t}\n\t\t}\n//\t\tLog.i(TAG, \"onChildParse  ObjectParser.onParse  key = \" + key + \"; child = \" + child);\n\n\t\treturn isEmpty ? null : child; // 只添加! isChildEmpty的值，可能数据库返回数据不够count\n\t}\n\n","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L632-L668","documentation":"Companion DoS guard to the array limit: each object parser counts parsed table objects and enforces parser.getMaxObjectCount() (default AbstractParser.MAX_OBJECT_COUNT = 5). Thrown when the number of object keys exceeds the maximum, with current count and limit in the message. The comment in source notes a TODO to use maxUpdateCount for batch writes.","triggerScenarios":"A request object nesting more than 5 table objects (e.g. a deep join graph with 6+ tables, or 6 sibling table keys at one level).","commonSituations":"Complex multi-table queries / deep association chains; batch inserts referencing many tables in one request; sharing one parser config across endpoints with different complexity needs.","solutions":["Reduce the number of tables per request — split into several requests or fetch associated data lazily.","Raise the limit deliberately: override getMaxObjectCount() in your parser subclass or set AbstractParser.MAX_OBJECT_COUNT, understanding the query-explosion implications.","For deep joins, verify each nesting level actually needs its own table object."],"exampleFix":"// server: allow 10 tables per request\npublic class MyParser extends AbstractParser<Long> {\n    @Override\n    public int getMaxObjectCount() { return 10; }\n}","handlingStrategy":"validation","validationCode":"int objects = countTableObjects(request); // walk nested maps counting table-key entries\nif (objects > 5) throw new IllegalArgumentException(\"too many table objects (\" + objects + \"), split the request\");","typeGuard":"function countTables(o: unknown): number {\n  if (o === null || typeof o !== 'object' || Array.isArray(o)) return 0;\n  return Object.entries(o).reduce((n, [k, v]) => n + (v !== null && typeof v === 'object' && !k.endsWith('[]') ? 1 + countTables(v) : n), 0);\n}\nconst withinObjectLimit = (req: object, max = 5) => countTables(req) <= max;","tryCatchPattern":null,"preventionTips":["Keep table-object count per request under getMaxObjectCount() (default 5).","Split wide join graphs across multiple calls.","If raising the limit, do it server-side deliberately and document the DoS trade-off."],"tags":["apijson","object-count","limit","dos-guard","configuration"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}