bytebase/bytebase · error

invalid empty workload identity identifier

Error message

invalid empty workload identity identifier

What it means

extractEmailFromUserIdentifier also handles workloadIdentities/{email} identifiers. When the workloadIdentities/ prefix is present but no email follows, it returns "invalid empty workload identity identifier". Without the email the workload identity principal cannot be resolved, so the identifier is rejected; identifiers matching none of the three prefixes get the distinct "invalid user identifier format" error instead.

Source

Thrown at backend/utils/utils.go:235

func extractEmailFromUserIdentifier(identifier string) (string, error) {
	if strings.HasPrefix(identifier, common.UserNamePrefix) {
		email := strings.TrimPrefix(identifier, common.UserNamePrefix)
		if email == "" {
			return "", errors.New("invalid empty user identifier")
		}
		return email, nil
	}
	if strings.HasPrefix(identifier, common.ServiceAccountNamePrefix) {
		email := strings.TrimPrefix(identifier, common.ServiceAccountNamePrefix)
		if email == "" {
			return "", errors.New("invalid empty service account identifier")
		}
		return email, nil
	}
	if strings.HasPrefix(identifier, common.WorkloadIdentityNamePrefix) {
		email := strings.TrimPrefix(identifier, common.WorkloadIdentityNamePrefix)
		if email == "" {
			return "", errors.New("invalid empty workload identity identifier")
		}
		return email, nil
	}
	return "", errors.Errorf("invalid user identifier format: %s", identifier)
}

// formatMemberNameByType returns the appropriate member name format based on user type.
// For regular users: users/{email}
// For service accounts: serviceAccounts/{email}
// For workload identities: workloadIdentities/{email}
func formatMemberNameByType(user *store.UserMessage) string {
	return common.FormatPrincipalMember(user.Email, user.Type)
}

View on GitHub (pinned to 1870550677)

Solutions

  1. Correct the workload identity binding so it carries the full "workloadIdentities/{email}" value, or delete the incomplete grant.
  2. Guard before the call: ensure strings.TrimPrefix(id, common.WorkloadIdentityNamePrefix) is non-empty.
  3. Fix the provisioning step that writes the identity so the email is always populated before the binding is created.

Example fix

// before
UpdateProjectPolicyFromRoleGrantIssue(ctx, "workloadIdentities/" + wi.Email)

// after
if wi.Email == "" {
    return fmt.Errorf("workload identity %s has no email yet; defer policy update", wi.Name)
}
UpdateProjectPolicyFromRoleGrantIssue(ctx, common.WorkloadIdentityNamePrefix + wi.Email)
Defensive patterns

Strategy: validation

Validate before calling

func hasNonEmptyWorkloadIdentityEmail(id string) bool {
    return strings.HasPrefix(id, "workloadIdentities/") && strings.TrimPrefix(id, "workloadIdentities/") != ""
}

Try / catch

email, err := extractEmailFromUserIdentifier(identifier)
if err != nil {
    log.Printf("unresolvable workload identity %q: %v", identifier, err)
    return nil
}

Prevention

When it happens

Trigger: UpdateProjectPolicyFromRoleGrantIssue processing a role grant whose member is the literal string "workloadIdentities/" with an empty email segment.

Common situations: Provisioning pipelines that create workload identity bindings before the identity's email is assigned; external IdP sync writing placeholder identifiers; truncation when identifiers are stored in fixed-width columns or logs.

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/d061406a3d73d680. Report an issue: GitHub.