{"record":{"id":"47ea1b14525cf1fd","repo":"elunez/eladmin","slug":"a-new-menu-cannot-already-have-an-id","errorCode":null,"errorMessage":"A new menu cannot already have an ID","messagePattern":"A new menu cannot already have an ID","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"eladmin-system/src/main/java/me/zhengjie/modules/system/rest/MenuController.java","lineNumber":128,"sourceCode":"                        menu.setSubCount(menu.getSubCount() - 1);\n                    }\n                }\n                menuDtos.addAll(menuDtoList);\n            }\n            // 编辑菜单时不显示自己以及自己下级的数据，避免出现PID数据环形问题\n            menuDtos = menuDtos.stream().filter(i -> !ids.contains(i.getId())).collect(Collectors.toSet());\n            return new ResponseEntity<>(menuService.buildTree(new ArrayList<>(menuDtos)),HttpStatus.OK);\n        }\n        return new ResponseEntity<>(menuService.getMenus(null),HttpStatus.OK);\n    }\n\n    @Log(\"新增菜单\")\n    @ApiOperation(\"新增菜单\")\n    @PostMapping\n    @PreAuthorize(\"@el.check('menu:add')\")\n    public ResponseEntity<Object> createMenu(@Validated @RequestBody Menu resources){\n        if (resources.getId() != null) {\n            throw new BadRequestException(\"A new \"+ ENTITY_NAME +\" cannot already have an ID\");\n        }\n        menuService.create(resources);\n        return new ResponseEntity<>(HttpStatus.CREATED);\n    }\n\n    @Log(\"修改菜单\")\n    @ApiOperation(\"修改菜单\")\n    @PutMapping\n    @PreAuthorize(\"@el.check('menu:edit')\")\n    public ResponseEntity<Object> updateMenu(@Validated(Menu.Update.class) @RequestBody Menu resources){\n        menuService.update(resources);\n        return new ResponseEntity<>(HttpStatus.NO_CONTENT);\n    }\n\n    @Log(\"删除菜单\")\n    @ApiOperation(\"删除菜单\")\n    @DeleteMapping\n    @PreAuthorize(\"@el.check('menu:del')\")","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/elunez/eladmin/blob/55fbf705956949697dbd68bf9003776609d3d029/eladmin-system/src/main/java/me/zhengjie/modules/system/rest/MenuController.java#L110-L146","documentation":"Thrown by MenuController.createMenu (line 128) when the POST /api/menus body includes a non-null id. Menus are hierarchical entities whose ids are database-assigned; the guard enforces the create-before-identity contract and returns 400 before menuService.create runs, preventing accidental row shadowing.","triggerScenarios":"Menu management tree dialog switching from edit to create without clearing the form; POSTing a Menu object fetched from GET /api/menus (e.g. to duplicate a menu); tooling that copies a whole menu subtree including ids.","commonSituations":"Front-end reuses the selected tree node (with id) as the base for a new sibling menu; menu duplication workflows; copying menu configuration between instances.","solutions":["Remove id from the payload before POST /api/menus; keep only pid and the fields you want.","When duplicating a menu, map explicitly to a new object instead of POSTing the fetched entity.","Reset the menu form (id = null, keep pid if creating a child) when the dialog opens in create mode."],"exampleFix":"// before (duplicate a menu by posting the fetched row)\naxios.post('/api/menus', this.selectedMenu)\n// after\nconst { id, children, ...payload } = this.selectedMenu;\naxios.post('/api/menus', payload)","handlingStrategy":"validation","validationCode":"const { id, children, createTime, ...payload } = selectedMenu;\naxios.post('/api/menus', payload); // duplication without id","typeGuard":"const isCreatePayload = (m) => m.id === undefined || m.id === null;","tryCatchPattern":null,"preventionTips":["When duplicating menus, map to an explicit new object.","Exclude the current node from the parent picker (also prevents pid = id)."],"tags":["rest-api","validation","eladmin","menu","crud"],"backgroundTag":null,"analyzedSha":"55fbf705956949697dbd68bf9003776609d3d029","analyzedAt":"2026-08-14T11:56:12.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}