{"record":{"id":"fe617f179dab0ae4","repo":"Tencent/APIJSON","slug":"subquery","errorCode":null,"errorMessage":"服务器内部错误，解析子查询 {}/{}:{ } 为 Subquery 对象失败！","messagePattern":"服务器内部错误，解析子查询 (.+?)/(.+?):(.+?) 为 Subquery 对象失败！","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java","lineNumber":432,"sourceCode":"\t@Override\n\tpublic boolean onParse(@NotNull String key, @NotNull Object value) throws Exception {\n\t\tif (key.endsWith(\"@\")) {  // StringUtil.isPath((String) value)) {\n\t\t\t// [] 内主表 position > 0 时，用来生成 SQLConfig<T, M, L> 的键值对全都忽略，不解析\n\t\t\tif (value instanceof Map<?, ?>) {  // key{}@ getRealKey, SQL 子查询对象，JSONRequest -> SQLConfig.getSQL\n\t\t\t\tString replaceKey = key.substring(0, key.length() - 1);\n\n\t\t\t\tM subquery = (M) value;\n\t\t\t\tString range = getString(subquery, KEY_SUBQUERY_RANGE);\n\t\t\t\tif (range != null && SUBQUERY_RANGE_ALL.equals(range) == false && SUBQUERY_RANGE_ANY.equals(range) == false) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"子查询 \" + path + \"/\" + key + \":{ range:value } 中 value 只能为 [\"\n                            + SUBQUERY_RANGE_ALL + \", \" + SUBQUERY_RANGE_ANY + \"] 中的一个！\");\n\t\t\t\t}\n\n\t\t\t\tL arr = parser.onArrayParse(subquery, path, key, true, null);\n\n\t\t\t\tM obj = arr == null || arr.isEmpty() ? null : JSON.get(arr, 0);\n\t\t\t\tif (obj == null) {\n\t\t\t\t\tthrow new Exception(\"服务器内部错误，解析子查询 \" + path + \"/\" + key + \":{ } 为 Subquery 对象失败！\");\n\t\t\t\t}\n\n\t\t\t\tString from = getString(subquery, apijson.JSONRequest.KEY_SUBQUERY_FROM);\n\t\t\t\tboolean isEmpty = StringUtil.isEmpty(from);\n\t\t\t\tM arrObj = isEmpty ? null : JSON.get(obj, from);\n\t\t\t\tif (isEmpty) {\n\t\t\t\t\tSet<Entry<String, Object>> set = obj.entrySet();\n\t\t\t\t\tfor (Entry<String, Object> e : set) {\n\t\t\t\t\t\tString k = e == null ? null : e.getKey();\n\t\t\t\t\t\tObject v = k == null ? null : e.getValue();\n\t\t\t\t\t\tif (v instanceof Map<?, ?> && JSONMap.isTableKey(k)) {\n\t\t\t\t\t\t\tfrom = k;\n\t\t\t\t\t\t\tarrObj = (M) v;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L414-L450","documentation":"Internal parser failure: for a 'key{}@' subquery, the parser runs the subquery object through onArrayParse and expects a non-empty array whose first element is a JSONObject. If the result array is null/empty or its first element is null, a generic Exception '服务器内部错误...' is thrown. It usually indicates the subquery object could not be structured into a table config at all (malformed inner object rather than a bad field).","triggerScenarios":"A 'key{}@' value that parses to no objects — e.g. {\"from\": \"X\"} with no table object inside, or an inner structure the array parser drops entirely (all keys filtered out), leaving arr empty so JSON.get(arr, 0) returns null.","commonSituations":"Subquery object missing its main table entry; inner table object consisting only of keys that get discarded during parsing; version changes in the array parser that alter which inner objects survive.","solutions":["Make sure the subquery object contains a well-formed main table object, e.g. \"id{}@\": { \"from\": \"Comment\", \"Comment\": { \"@column\": \"userId\" } }.","Check that the 'from' value matches a table key actually present inside the subquery object.","If it still fails, enable APIJSON logging to inspect what onArrayParse returned and simplify the subquery to the minimal from + table form."],"exampleFix":"// before\n\"id{}@\": { \"from\": \"Comment\", \"range\": \"ANY\" }\n// after\n\"id{}@\": { \"from\": \"Comment\", \"range\": \"ANY\", \"Comment\": { \"@column\": \"userId\" } }","handlingStrategy":"try-catch","validationCode":"// before sending: subquery object must contain a table object\nboolean hasTableObj(JSONObject sub) {\n  return sub.entrySet().stream().anyMatch(e -> e.getValue() instanceof Map && JSONMap.isTableKey(e.getKey()));\n}","typeGuard":"function isWellFormedSubquery(sub: Record<string, unknown>): boolean {\n  return Object.entries(sub).some(([k, v]) => v !== null && typeof v === 'object' && !Array.isArray(v) && /^[A-Za-z][A-Za-z0-9_]*$/.test(k));\n}","tryCatchPattern":"try { parse(request); } catch (Exception e) { if (e.getMessage() != null && e.getMessage().contains(\"解析子查询\")) { /* log subquery object, fix its structure */ } throw e; }","preventionTips":["Always include the main table object inside a 'key{}@' subquery.","Match 'from' to a real table key in the same object.","Test subqueries in isolation before embedding them in larger requests."],"tags":["apijson","subquery","internal-error","request-structure"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}