flipped-aurora/gin-vue-admin · error

primaryDeptId 需与 deptIds 一起传入(主部门必须属于本次追加或已有的部门集合);仅调整主部门请到前

Error message

primaryDeptId 需与 deptIds 一起传入(主部门必须属于本次追加或已有的部门集合);仅调整主部门请到前端组织管理页操作

What it means

In org_member_assigner, primaryDeptId is only honored when deptIds is also provided, because the primary department must belong to the department set being assigned (or already assigned). If the caller passes primaryDeptId without deptIds, the tool raises this error explicitly instead of silently dropping the field — the guard exists so callers don't mistakenly believe the primary department changed.

Source

Thrown at server/mcp/org_member_assigner.go:98

	deptIDs, err := parseUintList(args["deptIds"], "deptIds")
	if err != nil {
		return nil, err
	}
	positionIDs, err := parseUintList(args["positionIds"], "positionIds")
	if err != nil {
		return nil, err
	}
	if len(deptIDs) == 0 && len(positionIDs) == 0 {
		return nil, errors.New("deptIds 与 positionIds 至少需要传一个")
	}
	if len(deptIDs) > orgBatchLimit || len(positionIDs) > orgBatchLimit {
		return nil, fmt.Errorf("单次分配的部门/岗位数量各不能超过 %d 个", orgBatchLimit)
	}
	// primaryDeptId 只在设置部门(deptIds)时生效;仅传 primaryDeptId 不传 deptIds 会被静默丢弃,
	// 显式挡回避免调用方误以为主部门已变更
	if value, ok := args["primaryDeptId"]; ok && value != nil && len(deptIDs) == 0 {
		return nil, errors.New("primaryDeptId 需与 deptIds 一起传入(主部门必须属于本次追加或已有的部门集合);仅调整主部门请到前端组织管理页操作")
	}

	// 校验目标部门/岗位真实存在,把无效ID挡在写入之前
	if len(deptIDs) > 0 {
		deptIndex, err := fetchDeptIndex(ctx)
		if err != nil {
			return nil, err
		}
		for _, id := range deptIDs {
			if _, ok := deptIndex[id]; !ok {
				return nil, fmt.Errorf("部门 %d 不存在,可先用 query_org_structure 查询部门树", id)
			}
		}
	}
	for _, id := range positionIDs {
		query := url.Values{}
		query.Set("id", strconv.FormatUint(uint64(id), 10))
		if _, err := getUpstream[system.SysPosition](ctx, "/position/findPosition", query); err != nil {

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Pass deptIds together with primaryDeptId, ensuring the primary ID is in the current department set
  2. For a primary-department-only change, use the frontend organization management page as the error suggests
  3. Remove primaryDeptId from the payload if you did not intend to change the primary department
  4. Confirm the primaryDeptId value exists and matches one of the deptIds entries

Example fix

// before
args := map[string]interface{}{ "username": "alice", "positionIds": []uint{2}, "primaryDeptId": 3 }
// after
args := map[string]interface{}{ "username": "alice", "deptIds": []uint{3}, "positionIds": []uint{2}, "primaryDeptId": 3 }
Defensive patterns

Strategy: validation

Validate before calling

func validPrimaryDept(args map[string]interface{}) error {
  if v, ok := args["primaryDeptId"]; ok && v != nil {
    d, _ := args["deptIds"].([]interface{})
    if len(d) == 0 {
      return fmt.Errorf("primaryDeptId requires a non-empty deptIds list")
    }
  }
  return nil
}

Type guard

func primaryDeptAllowed(args map[string]interface{}) bool {
  v, present := args["primaryDeptId"]
  if !present || v == nil {
    return true
  }
  d, _ := args["deptIds"].([]interface{})
  return len(d) > 0
}

Try / catch

if err := validPrimaryDept(args); err != nil {
  // route primary-only changes to the frontend org management page instead
  return errRoutingToFrontend
}

Prevention

When it happens

Trigger: Calling org_member_assigner with a non-null args["primaryDeptId"] while deptIds is absent or empty (e.g. only positionIds given); a payload where deptIds was filtered down to zero entries but primaryDeptId remained.

Common situations: Callers wanting to change only a member's primary department via this tool; refactored code that stopped sending deptIds but kept primaryDeptId; template/prompt drift where the primaryDeptId example survived while deptIds was removed.

Related errors


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