{"record":{"id":"8b3153e6a5f83469","repo":"Tencent/APIJSON","slug":"request-allow-partial-update-fail-value-k","errorCode":null,"errorMessage":"后端 Request 表中 ALLOW_PARTIAL_UPDATE_FAIL:value 中 {key} 不合法！必须以 [] 结尾！","messagePattern":"后端 Request 表中 ALLOW_PARTIAL_UPDATE_FAIL:value 中 (.+?) 不合法！必须以 \\[\\] 结尾！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java","lineNumber":1231,"sourceCode":"\t\t// 校验重复<<<<<<<<<<<<<<<<<<<\n\t\tString[] uniques = StringUtil.split(unique);\n\t\tif (uniques != null && uniques.length > 0) {\n\t\t\tlong exceptId = getLongValue(real, finalIdKey);\n\t\t\tMap<String,Object> map = new HashMap<>();\n\t\t\tfor (String u : uniques) {\n\t\t\t\tmap.put(u, real.get(u));\n\t\t\t}\n\t\t\tverifyRepeat(name, map, exceptId, finalIdKey, parser);\n\t\t}\n\t\t// 校验重复>>>>>>>>>>>>>>>>>>>\n\n\t\t// 校验并配置允许批量增删改部分失败<<<<<<<<<<<<<<<<<<<\n\t\tString allowPartialUpdateFail = StringUtil.get(getString(target, ALLOW_PARTIAL_UPDATE_FAIL.name()));\n\t\tString[] partialFails = StringUtil.split(allowPartialUpdateFail);\n\t\tif (partialFails != null && partialFails.length > 0) {\n\t\t\tfor (String key : partialFails) {\n                if (isArrayKey(key) == false) {\n                    throw new IllegalArgumentException(\"后端 Request 表中 \" + ALLOW_PARTIAL_UPDATE_FAIL.name()\n                            + \":value 中 \" + key + \" 不合法！必须以 [] 结尾！\");\n                }\n                if (target.get(key) instanceof Collection == false) {\n                    throw new IllegalArgumentException(\"后端 Request 表中 \" + ALLOW_PARTIAL_UPDATE_FAIL.name()\n                            + \":value 中 \" + key + \" 对应的 \" + key + \":[] 不存在！\");\n                }\n\n                // 可能 Table[] 和 Table:alias[] 冲突  int index = key.indexOf(\":\");\n                // String k = index < 0 ? key.substring(0, key.length() - 2) : key.substring(0, index);\n                String k = key.substring(0, key.length() - 2);\n                if (k.isEmpty()) {\n                    throw new IllegalArgumentException(\"后端 Request 表中 \" + ALLOW_PARTIAL_UPDATE_FAIL.name()\n                            + \":value 中 \" + key + \" 不合法！[] 前必须有名字！\");\n                }\n\n\t\t\t\tAbstractSQLConfig.ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP.putIfAbsent(k, \"\");\n\t\t\t}\n\t\t}","sourceCodeStart":1213,"sourceCodeEnd":1249,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java#L1213-L1249","documentation":"Thrown while parsing ALLOW_PARTIAL_UPDATE_FAIL in the server-side Request table config: this optional setting lists which 'Table[]' batch keys are allowed to partially fail (some rows succeed, others fail, transaction not rolled back). Every entry must be an array key ending with '[]' (e.g. 'User[]'); an entry without that suffix is rejected with IllegalArgumentException because partial-failure semantics only exist for batch array operations.","triggerScenarios":"Backend admin sets ALLOW_PARTIAL_UPDATE_FAIL in the Request table to a value like \"User\" or \"User,Moment[]\" — any token that does not end with '[]' — and the next request that goes through AbstractVerifier.parse for that config throws immediately during verification, before SQL runs.","commonSituations":"Copying an ALLOW_PARTIAL_UPDATE_FAIL example but omitting the '[]' suffix; editing the Request table by hand instead of using the documented format; a JSON serialisation step stripping '[]' from the key; upgrading APIJSON to a version that added this strict check on previously tolerated config.","solutions":["Fix the value in the Request table so every token ends with '[]': e.g. ALLOW_PARTIAL_UPDATE_FAIL = \"User[]\" or \"User[],Moment[]\".","Verify with SQL: SELECT structure->'$.ALLOW_PARTIAL_UPDATE_FAIL' FROM Request WHERE ... and correct any token missing the suffix.","If partial failure is not needed, remove ALLOW_PARTIAL_UPDATE_FAIL entirely (null/empty is skipped by the check)."],"exampleFix":"// before\n{\"INSERT\":{\"ALLOW_PARTIAL_UPDATE_FAIL\":\"User\",\"User[]\":[]}}\n// after\n{\"INSERT\":{\"ALLOW_PARTIAL_UPDATE_FAIL\":\"User[]\",\"User[]\":[]}}","handlingStrategy":"validation","validationCode":"private static final Pattern ARR_KEY = Pattern.compile(\"^\\\\w+\\\\[\\\\]$\");\nvoid checkPartialFailConfig(String value) {\n  if (value == null || value.isEmpty()) return;\n  for (String tok : value.split(\"[\\\\s,]+\")) {\n    if (!ARR_KEY.matcher(tok).matches())\n      throw new IllegalStateException(\"ALLOW_PARTIAL_UPDATE_FAIL token '\" + tok + \"' must end with []\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try { verifier.parse(...); }\ncatch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"ALLOW_PARTIAL_UPDATE_FAIL\")) {\n    // backend config defect — fix the Request row; do not retry\n    log.error(\"Fix Request table ALLOW_PARTIAL_UPDATE_FAIL: {}\", e.getMessage());\n  }\n  throw e;\n}","preventionTips":["Never hand-edit ALLOW_PARTIAL_UPDATE_FAIL; generate it from the same structure that defines the 'Table[]':[] keys.","Add a startup assertion that walks all Request rows and validates every ALLOW_PARTIAL_UPDATE_FAIL token matches ^\\w+\\[\\]$."],"tags":["apijson","server-config","request-table","batch-operations"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}