bytebase/bytebase · error

no fields to update

Error message

no fields to update

What it means

UpdateRole in backend/store/role.go builds a SET clause from the Role patch fields (e.g. permissions). If none are set, set.Len() == 0 and the store returns "no fields to update" rather than issuing an UPDATE with an empty SET against the role table matched by resource_id and workspace.

Source

Thrown at backend/store/role.go:232

	if v := patch.Name; v != nil {
		set.Comma("name = ?", *v)
	}
	if v := patch.Description; v != nil {
		set.Comma("description = ?", *v)
	}
	if v := patch.Permissions; v != nil {
		p := &storepb.RolePermissions{}
		for k := range *v {
			p.Permissions = append(p.Permissions, k)
		}
		permissionBytes, err := protojson.Marshal(p)
		if err != nil {
			return nil, err
		}
		set.Comma("permissions = ?", permissionBytes)
	}
	if set.Len() == 0 {
		return nil, errors.New("no fields to update")
	}

	q := qb.Q().Space(`
		UPDATE role
		SET ?
		WHERE resource_id = ? AND workspace = ?
		RETURNING name, description, permissions
	`, set, patch.ResourceID, patch.Workspace)

	query, args, err := q.ToSQL()
	if err != nil {
		return nil, errors.Wrapf(err, "failed to build sql")
	}

	role := &RoleMessage{
		ResourceID:  patch.ResourceID,
		Permissions: map[permission.Permission]bool{},
	}

View on GitHub (pinned to 1870550677)

Solutions

  1. Set Permissions (or another patchable field) on the role update message before calling UpdateRole
  2. Validate in the API layer that the update mask covers at least one patchable field and return CodeInvalidArgument otherwise
  3. Skip the write and return the existing role when the request is a true no-op

Example fix

// before
_, err := store.UpdateRole(ctx, &store.RoleMessage{ResourceID: roleID, Workspace: ws})
// after
_, err := store.UpdateRole(ctx, &store.RoleMessage{ResourceID: roleID, Workspace: ws, Permissions: perms})
Defensive patterns

Strategy: validation

Validate before calling

if msg.Permissions == nil {
	return connect.NewError(connect.CodeInvalidArgument, errors.New("role update requires permissions"))
}

Try / catch

role, err := store.UpdateRole(ctx, msg)
if err != nil && strings.Contains(err.Error(), "no fields to update") {
	return connect.NewError(connect.CodeInvalidArgument, errors.New("empty role update"))
}

Prevention

When it happens

Trigger: Calling UpdateRole with a message lacking any patchable field — an API role update whose mask selects nothing, or a permissions update path where the permission list conversion failed before the set.Comma call.

Common situations: Client submits an empty role edit; an admin UI saves a form with no changes; handler filters masked fields and the mask contains only unsupported paths like title-only renames not backed by patch fields.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/f255dba821c8ced7. Report an issue: GitHub.