flipped-aurora/gin-vue-admin · error

sys_base_menus子菜单初始化失败!

Error message

sys_base_menus子菜单初始化失败!

What it means

Thrown by the menu initializer when inserting the second-level (child) seed menus into sys_base_menus fails. Child menus carry ParentId values resolved from menuNameMap built from the successfully inserted parent rows, so this error means the parent batch succeeded but the child batch's db.Create failed.

Source

Thrown at server/source/system/menu.go:144

		// AI 工坊
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["ai"], Path: "mcpTool", Name: "mcpTool", Component: "plugin/ai/view/mcp/mcp.vue", Sort: 1, Meta: Meta{Title: "Mcp Tools模板", Icon: "grid"}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["ai"], Path: "mcpTest", Name: "mcpTest", Component: "plugin/ai/view/mcp/mcpTest.vue", Sort: 2, Meta: Meta{Title: "Mcp Tools管理", Icon: "connection"}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["ai"], Path: "mcpApi", Name: "McpApi", Component: "plugin/ai/view/mcpApi/index.vue", Sort: 3, Meta: Meta{Title: "AI MCP构建", Icon: "set-up"}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["ai"], Path: "skills", Name: "Skills", Component: "plugin/ai/view/skills/index.vue", Sort: 4, Meta: Meta{Title: "Skills管理", Icon: "edit-pen"}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["ai"], Path: "cli", Name: "Cli", Component: "plugin/ai/view/cli/index.vue", Sort: 5, Meta: Meta{Title: "AI CLI管理", Icon: "monitor", KeepAlive: true}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["ai"], Path: "picture", Name: "picture", Component: "plugin/ai/view/picture/picture.vue", Sort: 6, Meta: Meta{Title: "AI页面绘制", Icon: "picture"}},

		// 插件系统
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["plugin"], Path: "https://plugin.gin-vue-admin.com/", Name: "https://plugin.gin-vue-admin.com/", Component: "https://plugin.gin-vue-admin.com/", Sort: 0, Meta: Meta{Title: "插件市场", Icon: "shop"}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["plugin"], Path: "installPlugin", Name: "installPlugin", Component: "view/systemTools/installPlugin/index.vue", Sort: 1, Meta: Meta{Title: "插件安装", Icon: "box"}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["plugin"], Path: "pubPlug", Name: "pubPlug", Component: "view/systemTools/pubPlug/pubPlug.vue", Sort: 3, Meta: Meta{Title: "打包插件", Icon: "suitcase"}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["plugin"], Path: "plugin-email", Name: "plugin-email", Component: "plugin/email/view/index.vue", Sort: 4, Meta: Meta{Title: "邮件插件", Icon: "message"}},
		{MenuLevel: 1, Hidden: false, ParentId: menuNameMap["plugin"], Path: "anInfo", Name: "anInfo", Component: "plugin/announcement/view/info.vue", Sort: 5, Meta: Meta{Title: "公告管理[示例]", Icon: "bell"}},
	}

	// 创建子菜单
	if err = db.Create(&childMenus).Error; err != nil {
		return ctx, errors.Wrap(err, SysBaseMenu{}.TableName()+"子菜单初始化失败!")
	}

	// 组合所有菜单作为返回结果
	allEntities := append(allMenus, childMenus...)
	next = context.WithValue(ctx, i.InitializerName(), allEntities)
	return next, nil
}

func (i *initMenu) DataInserted(ctx context.Context) bool {
	db, ok := ctx.Value("db").(*gorm.DB)
	if !ok {
		return false
	}
	if errors.Is(db.Where("path = ?", "dashboard").First(&SysBaseMenu{}).Error, gorm.ErrRecordNotFound) { // 判断是否存在数据
		return false
	}
	return true
}

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Inspect the wrapped GORM error (duplicate key vs constraint vs connection)
  2. Drop/TRUNCATE sys_base_menus so both parent and child phases re-run atomically against a clean table
  3. Ensure AutoMigrate of SysBaseMenu and SysBaseMenuParameter ran before init
  4. Only run initialization once per database (guard with DataInserted) and avoid concurrent init runs
  5. Check for pre-existing menus with colliding Path/Name and rename/remove them

Example fix

// before: partial seed leaves parents, child insert hits duplicate path
ctx, err = initMenu{}.InitializeData(ctx)
// after: clean slate then init
_ = db.Where("1 = 1").Delete(&system.SysBaseMenu{})
if err := db.AutoMigrate(&system.SysBaseMenu{}); err != nil { return err }
ctx, err = initMenu{}.InitializeData(ctx)
Defensive patterns

Strategy: validation

Validate before calling

var count int64
if err := db.Model(&system.SysBaseMenu{}).Count(&count).Error; err != nil { return err }
if count > 0 { return nil } // skip full reseed, avoids partial parent/child state
if err := db.AutoMigrate(&system.SysBaseMenu{}); err != nil { return err }

Type guard

func parentsSeeded(ctx context.Context) ([]system.SysBaseMenu, bool) {
    menus, ok := ctx.Value(new(initMenu).InitializerName()).([]system.SysBaseMenu)
    return menus, ok && len(menus) > 0
}

Try / catch

ctx, err = initMenu{}.InitializeData(ctx)
if err != nil {
    if strings.Contains(err.Error(), "子菜单初始化失败") {
        log.Printf("child menu insert failed, check duplicate paths/parents: %v", errors.Cause(err))
    }
    return err
}

Prevention

When it happens

Trigger: db.Create(&childMenus) fails: missing table, duplicate path/name unique key from prior seeding, ParentId referencing a parent deleted between phases, constraint violations, or DB failure mid-insert.

Common situations: Partially completed init from a crashed previous run left parent rows but conflicting child rows; another admin inserted a menu with the same Path/Name; schema drift after upgrading gin-vue-admin added NOT NULL columns; DB connection dropped between the two Create batches.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/a2b27f0b6a7c06d6. Report an issue: GitHub.