flipped-aurora/gin-vue-admin · error
菜单 %d 不存在,可先用 list_all_menus 查询全部菜单
Error message
菜单 %d 不存在,可先用 list_all_menus 查询全部菜单
What it means
Each requested menu ID must exist in the flattened index of the server's menu list. An unknown ID is rejected with a hint to use the list_all_menus tool to discover valid IDs. This prevents writing menu-authority rows for menus that do not exist.
Source
Thrown at server/mcp/role_menu_assigner.go:83
}
if err := requireNonEmptyList(menuIDs, "menuIds"); err != nil {
return nil, err
}
if len(menuIDs) > orgBatchLimit {
return nil, fmt.Errorf("单次授权菜单数量不能超过 %d 个", orgBatchLimit)
}
// 全量基础菜单:存在性校验、父链补齐、写回时的完整菜单对象都从这里取
allResp, err := postUpstream[[]system.SysBaseMenu](ctx, "/menu/getMenuList", map[string]any{})
if err != nil {
return nil, fmt.Errorf("获取菜单列表失败: %w", err)
}
menuIndex := make(map[uint]system.SysBaseMenu)
flattenBaseMenus(allResp.Data, menuIndex)
for _, id := range menuIDs {
if _, ok := menuIndex[id]; !ok {
return nil, fmt.Errorf("菜单 %d 不存在,可先用 list_all_menus 查询全部菜单", id)
}
}
// 角色当前授权(先读,防覆盖丢权)
currentResp, err := postUpstream[map[string][]system.SysMenu](ctx, "/menu/getMenuAuthority", map[string]any{
"authorityId": authorityID,
})
if err != nil {
return nil, fmt.Errorf("获取角色当前菜单授权失败: %w", err)
}
currentIDs := make([]uint, 0)
for _, menu := range currentResp.Data["menus"] {
id := menu.MenuId
if id == 0 {
id = menu.ID
}
if id != 0 && !containsUint(currentIDs, id) {
currentIDs = append(currentIDs, id)View on GitHub (pinned to 3136500ef3)
Solutions
- Call the list_all_menus MCP tool to get the current valid menu IDs and correct the list
- Remove or replace the stale ID in menuIds
- Install/enable the missing plugin if the menu belongs to a plugin
- Re-seed or restore the menu if it was accidentally deleted server-side
Example fix
// before
menuIds := []uint{1, 2, 333} // 333 doesn't exist
// after
// verify via list_all_menus first
menuIds := []uint{1, 2, 18} Defensive patterns
Strategy: validation
Validate before calling
// fetch valid menu IDs via list_all_menus first
all, err := listAllMenus(ctx)
if err != nil {
return err
}
valid := make(map[uint]struct{}, len(all))
for _, m := range all {
valid[m.ID] = struct{}{}
}
for _, id := range menuIDs {
if _, ok := valid[id]; !ok {
return fmt.Errorf("menu %d not found", id)
}
} Type guard
func allMenusExist(ids []uint, index map[uint]struct{}) bool {
for _, id := range ids {
if _, ok := index[id]; !ok {
return false
}
}
return true
} Prevention
- Discover IDs via list_all_menus rather than hardcoding
- Re-sync IDs after re-seeding menus or switching environments
- Install required plugins before referencing their menus
When it happens
Trigger: Calling the assign-menus tool with a menuIds entry absent from the server's menu tree: typo, ID from another environment, soft-deleted menu, or an ID belonging to a plugin not installed.
Common situations: Hardcoded menu IDs drifting across environments after re-seeding menus; menu removed in a newer gva version; plugin menus missing because the plugin wasn't installed.
Related errors
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/9742f7ece9b9480f.
Report an issue: GitHub.