paascloud/paascloud-master · error · UacBizException

UAC10013008

UAC10013008

Error message

删除菜单失败, menuId=%s

What it means

UacBizException UAC10013008 thrown when deleteUacMenuById's final delete (uacMenuMapper.deleteByPrimaryKey(id)) affects fewer than 1 row, meaning the menu row disappeared between the existence check and the delete, or the delete statement failed to match. An error log '删除菜单失败 menuId=...' is written first.

Solutions

  1. Verify the menu no longer exists — if it is already gone, treat the delete as idempotent success and skip the error.
  2. Deduplicate delete requests on the client (disable button after first click) to avoid racing deletes.
  3. Confirm the deleteByPrimaryKey SQL matches rows by the correct primary key column in the mapper XML.
  4. Inspect DB logs for row-lock or transaction issues around the delete.

Example fix

// before: fail hard on 0 rows
int result = uacMenuMapper.deleteByPrimaryKey(id);
if (result < 1) { throw new UacBizException(ErrorCodeEnum.UAC10013008, id); }
// after: idempotent delete
int result = uacMenuMapper.deleteByPrimaryKey(id);
if (result < 1 && uacMenuMapper.selectByPrimaryKey(id) != null) {
  throw new UacBizException(ErrorCodeEnum.UAC10013008, id);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (uacMenuMapper.selectByPrimaryKey(id) == null) { return; /* already gone */ }

Type guard

boolean menuStillExists(Long id) { return uacMenuMapper.selectByPrimaryKey(id) != null; }

Try / catch

try {
  uacMenuService.deleteUacMenuById(id);
} catch (UacBizException e) {
  if ("UAC10013008".equals(e.getCode()) && uacMenuMapper.selectByPrimaryKey(id) == null) {
    return; // raced with another delete; treat as success
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling deleteUacMenuById(id) where the row passed the initial existence check but was deleted concurrently by another transaction before deleteByPrimaryKey ran, or where the primary-key delete matched 0 rows for any reason.

Common situations: Two admins deleting the same menu simultaneously; duplicate delete requests from a retried HTTP call racing each other; read-replica/primary lag making the existence check pass on stale data.

Related errors


AI-assisted analysis of paascloud/paascloud-master@781281a950 (2026-09-10). Data as JSON: /api/errors/dc48bb1d10b4ff78. Report an issue: GitHub.

Appendix: source

Thrown at paascloud-provider/paascloud-provider-uac/src/main/java/com/paascloud/provider/service/impl/UacMenuServiceImpl.java:187

		// 获取当前菜单信息
		UacMenu uacMenuQuery = new UacMenu();
		uacMenuQuery.setId(id);
		uacMenuQuery = mapper.selectOne(uacMenuQuery);
		if (PublicUtil.isEmpty(uacMenuQuery)) {
			throw new UacBizException(ErrorCodeEnum.UAC10013003, id);
		}

		// 删除菜单与角色的关联关系
		UacRoleMenu uacRoleMenu = new UacRoleMenu();
		uacRoleMenu.setMenuId(id);
		uacRoleMenuService.delete(uacRoleMenu);


		// 删除菜单
		result = uacMenuMapper.deleteByPrimaryKey(id);
		if (result < 1) {
			logger.error("删除菜单失败 menuId={}", id);
			throw new UacBizException(ErrorCodeEnum.UAC10013008, id);
		}

		// 删除权限
		// TODO 应该先查询再删除
		uacActionService.deleteByMenuId(id);

		// 修改当前删除菜单的父菜单是否是叶子节点
		UacMenu updateParentUacMenu = new UacMenu();
		updateParentUacMenu.setId(uacMenuQuery.getPid());
		updateParentUacMenu.setLeaf(MenuConstant.MENU_LEAF_YES);
		// 是二三级
		if (Objects.equals(MenuConstant.MENU_LEVEL_TWO, uacMenuQuery.getLevel()) || Objects.equals(MenuConstant.MENU_LEVEL_THREE, uacMenuQuery.getLevel())) {
			// 查询是否是叶子节点
			int count = uacMenuMapper.selectMenuChildCountByPid(uacMenuQuery.getPid());
			if (count == 0) {
				uacMenuMapper.updateByPrimaryKeySelective(updateParentUacMenu);
			}
		}

View on GitHub (pinned to 781281a950)