{"record":{"id":"a4190bcc3c9a534d","repo":"jeecgboot/JeecgBoot","slug":"error-a4190b","errorCode":null,"errorMessage":"未找到菜单信息","messagePattern":"未找到菜单信息","errorType":"exception","errorClass":"JeecgBootException","httpStatus":null,"severity":"error","filePath":"jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java","lineNumber":81,"sourceCode":"\t\tsysPermissionMapper.backupVue2Menu();\n\t\tsysPermissionMapper.changeVue3Menu();\n\t}\n\n\t@Override\n\tpublic List<TreeModel> queryListByParentId(String parentId) {\n\t\treturn sysPermissionMapper.queryListByParentId(parentId);\n\t}\n\n\t/**\n\t  * 真实删除\n\t */\n\t@Override\n\t@Transactional(rollbackFor = Exception.class)\n\t@CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE,allEntries=true)\n\tpublic void deletePermission(String id) throws JeecgBootException {\n\t\tSysPermission sysPermission = this.getById(id);\n\t\tif(sysPermission==null) {\n\t\t\tthrow new JeecgBootException(\"未找到菜单信息\");\n\t\t}\n\t\tString pid = sysPermission.getParentId();\n\t\tif(oConvertUtils.isNotEmpty(pid)) {\n\t\t\tLong count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, pid));\n\t\t\tif(count==1) {\n\t\t\t\t//若父节点无其他子节点，则该父节点是叶子节点\n\t\t\t\tthis.sysPermissionMapper.setMenuLeaf(pid, 1);\n\t\t\t}\n\t\t}\n\t\tsysPermissionMapper.deleteById(id);\n\t\t// 该节点可能是子节点但也可能是其它节点的父节点,所以需要级联删除\n\t\tthis.removeChildrenBy(sysPermission.getId());\n\t\t//关联删除\n\t\tMap map = new HashMap(5);\n\t\tmap.put(\"permission_id\",id);\n\t\t//删除数据规则\n\t\tthis.deletePermRuleByPermId(id);\n\t\t//删除角色授权表","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java#L63-L99","documentation":"Thrown by SysPermissionServiceImpl.deletePermission (real/hard delete) when this.getById(id) returns null — the menu/permission to delete does not exist. This JeecgBootException prevents cascading deletes on a non-existent record. The method is transactional and evicts the data-permissions cache.","triggerScenarios":"Calling deletePermission with a permission ID that was already deleted (physically), doesn't exist, or is from a different tenant. The ID comes from the controller's delete endpoint.","commonSituations":"Double-click on a delete button causing two delete requests for the same menu; a menu was already hard-deleted by another admin; a stale menu ID from an outdated frontend menu tree.","solutions":["Add frontend debounce/loading state on the delete button to prevent duplicate requests.","Refresh the menu/permission tree after a delete before attempting another.","If calling programmatically, verify the permission exists before calling deletePermission.","Consider catching JeecgBootException at the controller to return a friendly 'already deleted' message."],"exampleFix":"// before\nSysPermission sysPermission = this.getById(id);\nif (sysPermission == null) {\n    throw new JeecgBootException(\"未找到菜单信息\");\n}\n\n// after — controller handles gracefully\ntry {\n    permissionService.deletePermission(id);\n} catch (JeecgBootException e) {\n    if (e.getMessage().contains(\"未找到\")) {\n        return Result.OK(\"菜单已不存在，可能已被删除\");\n    }\n    throw e;\n}","handlingStrategy":"validation","validationCode":"// Validate permission exists before deleting\nSysPermission perm = permissionService.getById(id);\nif (perm == null) {\n    return Result.OK(\"菜单已不存在，可能已被删除\");\n}\npermissionService.deletePermission(id);","typeGuard":"public boolean isPermissionExists(String id) {\n    if (id == null || id.trim().isEmpty()) return false;\n    return permissionService.getById(id) != null;\n}","tryCatchPattern":"try {\n    permissionService.deletePermission(id);\n} catch (JeecgBootException e) {\n    if (e.getMessage().contains(\"未找到菜单信息\")) {\n        return Result.OK(\"菜单已不存在，可能已被删除\");\n    }\n    throw e;\n}","preventionTips":["Add loading state on delete buttons to prevent duplicate requests.","Refresh the menu tree after deletion.","Treat 'not found' on delete as idempotent success rather than an error."],"tags":["jeecg-boot","permission","menu","null-check","business-exception"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}