flipped-aurora/gin-vue-admin · error

不能将字典详情设置为自己或其子项的父级

Error message

不能将字典详情设置为自己或其子项的父级

What it means

UpdateSysDictionaryDetail rejects updates that would make a detail's parent be itself or one of its own descendants, which would create a cycle in the parent/child hierarchy. It uses checkCircularReference to walk the proposed parent's ancestry chain.

Source

Thrown at server/service/system/sys_dictionary_detail.go:84

//@author: [piexlmax](https://github.com/piexlmax)
//@function: UpdateSysDictionaryDetail
//@description: 更新字典详情数据
//@param: sysDictionaryDetail *model.SysDictionaryDetail
//@return: err error

func (dictionaryDetailService *DictionaryDetailService) UpdateSysDictionaryDetail(ctx context.Context, sysDictionaryDetail *system.SysDictionaryDetail) (err error) {
	// 如果更新了父级ID,需要重新计算层级和路径
	if sysDictionaryDetail.ParentID != nil {
		var parent system.SysDictionaryDetail
		err = global.GVA_DB.WithContext(ctx).First(&parent, *sysDictionaryDetail.ParentID).Error
		if err != nil {
			return err
		}

		// 检查循环引用
		if dictionaryDetailService.checkCircularReference(ctx, sysDictionaryDetail.ID, *sysDictionaryDetail.ParentID) {
			return fmt.Errorf("不能将字典详情设置为自己或其子项的父级")
		}

		sysDictionaryDetail.Level = parent.Level + 1
		if parent.Path == "" {
			sysDictionaryDetail.Path = strconv.Itoa(int(parent.ID))
		} else {
			sysDictionaryDetail.Path = parent.Path + "," + strconv.Itoa(int(parent.ID))
		}
	} else {
		sysDictionaryDetail.Level = 0
		sysDictionaryDetail.Path = ""
	}

	err = global.GVA_DB.WithContext(ctx).Save(sysDictionaryDetail).Error
	if err != nil {
		return err
	}

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Choose a ParentID outside the detail's own subtree
  2. Verify the proposed parent's Path does not start with the detail's Path before saving
  3. In UI, disable drop targets that are the node itself or its descendants

Example fix

// before
await updateDetail({ id: node.id, parentId: node.id }) // cycle
// after
const parent = await getDetail(proposedParentId)
if (!parent.path.startsWith(`${node.path}/`)) {
  await updateDetail({ id: node.id, parentId: proposedParentId })
}
Defensive patterns

Strategy: validation

Validate before calling

const target = detailMap[proposedParentId]
if (target.path.startsWith(`${node.path}/`)) {
  throw new Error('cannot move node into its own subtree')
}

Try / catch

try {
  await updateDetail(payload)
} catch (e) {
  if (e.message.includes('父级')) {
    ElMessage.error('不能移动到自身或子节点')
  }
}

Prevention

When it happens

Trigger: Calling UpdateSysDictionaryDetail with a ParentID equal to the detail's own ID, or pointing at any detail whose ancestor chain contains the detail being updated.

Common situations: Bulk edits or drag-and-drop tree UIs moving a subtree under its own descendant; scripts re-parenting details without cycle checks; concurrent edits creating transient loops.

Related errors


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