{"record":{"id":"f535afe6e399e9f1","repo":"Tencent/APIJSON","slug":"error-f535af","errorCode":null,"errorMessage":"没权限访问或对象不存在！","messagePattern":"没权限访问或对象不存在！","errorType":"exception","errorClass":"IllegalAccessException","httpStatus":403,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java","lineNumber":242,"sourceCode":"\t\t\t\t//导致后面 rs.getMetaData() 报错 Operation not allowed after ResultSet closed\t\tresult.put(\"moreResults\", statement.getMoreResults());\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tRequestMethod method = config.getMethod();\r\n\t\t\t\tswitch (method) {\r\n\t\t\t\tcase POST:\r\n\t\t\t\tcase PUT:\r\n\t\t\t\tcase DELETE:\r\n\t\t\t\t\tif (isExplain == false) { //只有 SELECT 才能 EXPLAIN\r\n\t\t\t\t\t\texecutedSQLCount ++;\r\n\t\t\t\t\t\texecutedSQLStartTime = System.currentTimeMillis();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tint updateCount = executeUpdate(config);\r\n\t\t\t\t\tif (isExplain == false) {\r\n\t\t\t\t\t\texecutedSQLDuration += System.currentTimeMillis() - executedSQLStartTime;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (updateCount <= 0) {\r\n\t\t\t\t\t\tthrow new IllegalAccessException(\"没权限访问或对象不存在！\");  // NotExistException 会被 catch 转为成功状态\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// updateCount>0时收集结果。例如更新操作成功时，返回count(affected rows)、id字段\r\n\t\t\t\t\tresult = parser.newSuccessResult();  // TODO 对 APIAuto 及其它现有的前端/客户端影响比较大，暂时还是返回 code 和 msg，5.0 再移除  JSON.createJSONObject();\r\n\r\n\t\t\t\t\t//id,id{}至少一个会有，一定会返回，不用抛异常来阻止关联写操作时前面错误导致后面无条件执行！\r\n\t\t\t\t\tresult.put(JSONResponse.KEY_COUNT, updateCount);//返回修改的记录数\r\n\r\n\t\t\t\t\tString idKey = config.getIdKey();\r\n\t\t\t\t\tif (config.getId() != null) {\r\n\t\t\t\t\t\tresult.put(idKey, config.getId());\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (config.getIdIn() != null) {\r\n\t\t\t\t\t\tresult.put(idKey + \"[]\", config.getIdIn());\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (method == RequestMethod.PUT || method == RequestMethod.DELETE) {\r\n\t\t\t\t\t\tconfig.setMethod(RequestMethod.GET);\r","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java#L224-L260","documentation":"Thrown as IllegalAccessException by AbstractSQLExecutor after a PUT/DELETE statement executes and updateCount <= 0. Zero affected rows means no row matched the WHERE conditions, which for writes is indistinguishable from 'no permission for that object' — so the request fails instead of returning success (the comment notes a NotExist-like success conversion must not happen here).","triggerScenarios":"PUT/DELETE where the id/condition matches nothing: record already deleted, wrong id, condition on a column value that changed, or row-level permission filtering that rewrites the WHERE to match nothing.","commonSituations":"Concurrent deletes (double submit), stale client data after another user's update, permission (visitor vs own data) rules excluding the row, or weak conditions like name-based matching.","solutions":["Re-check that the target row exists (e.g. a prior GET with the same conditions/permissions) before retrying the write.","Prefer addressing rows by primary key (id) rather than by mutable column values.","Handle the 404-ish outcome in the client: treat as 'already deleted / no permission' and reconcile UI state instead of blindly retrying.","If permission rules are the cause, adjust the request session/role or the access model for that table."],"exampleFix":"// before\n{\"User\": {\"id\": 123, \"name\": \"old\"}}  // name already changed by someone else\n// after\n{\"User\": {\"id\": 123}}","handlingStrategy":"try-catch","validationCode":"const r = await apijson.get({ [table]: { id } });\nif (!r[table] || Object.keys(r[table]).length === 0) throw new NotFoundError(`${table}#${id}`);\nawait apijson.put({ [table]: { id, ...changes } });","typeGuard":null,"tryCatchPattern":"try {\n  await apijson.put(body);\n} catch (e) {\n  if (e instanceof IllegalAccessException || /没权限访问或对象不存在/.test(e.message)) {\n    // row gone or not yours: reconcile UI, do not blind-retry\n    return { ok: false, reason: 'gone-or-forbidden' };\n  }\n  throw e;\n}","preventionTips":["Address writes by primary key only.","Handle double-submit (disable button while pending) to avoid racing deletes.","Treat updateCount 0 as an expected outcome and surface it to the user."],"tags":["apijson","update-count","write","concurrency","permission"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}