{"record":{"id":"d061406a3d73d680","repo":"bytebase/bytebase","slug":"invalid-empty-workload-identity-identifier","errorCode":null,"errorMessage":"invalid empty workload identity identifier","messagePattern":"invalid empty workload identity identifier","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/utils/utils.go","lineNumber":235,"sourceCode":"func extractEmailFromUserIdentifier(identifier string) (string, error) {\n\tif strings.HasPrefix(identifier, common.UserNamePrefix) {\n\t\temail := strings.TrimPrefix(identifier, common.UserNamePrefix)\n\t\tif email == \"\" {\n\t\t\treturn \"\", errors.New(\"invalid empty user identifier\")\n\t\t}\n\t\treturn email, nil\n\t}\n\tif strings.HasPrefix(identifier, common.ServiceAccountNamePrefix) {\n\t\temail := strings.TrimPrefix(identifier, common.ServiceAccountNamePrefix)\n\t\tif email == \"\" {\n\t\t\treturn \"\", errors.New(\"invalid empty service account identifier\")\n\t\t}\n\t\treturn email, nil\n\t}\n\tif strings.HasPrefix(identifier, common.WorkloadIdentityNamePrefix) {\n\t\temail := strings.TrimPrefix(identifier, common.WorkloadIdentityNamePrefix)\n\t\tif email == \"\" {\n\t\t\treturn \"\", errors.New(\"invalid empty workload identity identifier\")\n\t\t}\n\t\treturn email, nil\n\t}\n\treturn \"\", errors.Errorf(\"invalid user identifier format: %s\", identifier)\n}\n\n// formatMemberNameByType returns the appropriate member name format based on user type.\n// For regular users: users/{email}\n// For service accounts: serviceAccounts/{email}\n// For workload identities: workloadIdentities/{email}\nfunc formatMemberNameByType(user *store.UserMessage) string {\n\treturn common.FormatPrincipalMember(user.Email, user.Type)\n}\n","sourceCodeStart":217,"sourceCodeEnd":249,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/utils/utils.go#L217-L249","documentation":"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.","triggerScenarios":"UpdateProjectPolicyFromRoleGrantIssue processing a role grant whose member is the literal string \"workloadIdentities/\" with an empty email segment.","commonSituations":"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.","solutions":["Correct the workload identity binding so it carries the full \"workloadIdentities/{email}\" value, or delete the incomplete grant.","Guard before the call: ensure strings.TrimPrefix(id, common.WorkloadIdentityNamePrefix) is non-empty.","Fix the provisioning step that writes the identity so the email is always populated before the binding is created."],"exampleFix":"// before\nUpdateProjectPolicyFromRoleGrantIssue(ctx, \"workloadIdentities/\" + wi.Email)\n\n// after\nif wi.Email == \"\" {\n    return fmt.Errorf(\"workload identity %s has no email yet; defer policy update\", wi.Name)\n}\nUpdateProjectPolicyFromRoleGrantIssue(ctx, common.WorkloadIdentityNamePrefix + wi.Email)","handlingStrategy":"validation","validationCode":"func hasNonEmptyWorkloadIdentityEmail(id string) bool {\n    return strings.HasPrefix(id, \"workloadIdentities/\") && strings.TrimPrefix(id, \"workloadIdentities/\") != \"\"\n}","typeGuard":null,"tryCatchPattern":"email, err := extractEmailFromUserIdentifier(identifier)\nif err != nil {\n    log.Printf(\"unresolvable workload identity %q: %v\", identifier, err)\n    return nil\n}","preventionTips":["Defer binding creation until the workload identity's email is assigned","Validate identifiers on ingest from external IdP syncs","Keep identifiers as full strings in a single field to avoid truncation bugs"],"tags":["go","validation","iam","workload-identity"],"backgroundTag":"empty-required-field","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}