{"record":{"id":"956eed21a20d2edb","repo":"pulumi/pulumi","slug":"creating-organization-role-w","errorCode":null,"errorMessage":"creating organization role: %w","messagePattern":"creating organization role: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/backend/httpstate/client/client.go","lineNumber":1930,"sourceCode":"\tqueryObj := struct {\n\t\tUXPurpose string `url:\"uxPurpose,omitempty\"`\n\t}{UXPurpose: uxPurpose}\n\n\tvar resp apitype.ListRolesResponse\n\tif err := pc.restCall(ctx, \"GET\", path, queryObj, nil, &resp); err != nil {\n\t\treturn nil, fmt.Errorf(\"listing organization roles: %w\", err)\n\t}\n\treturn resp.Roles, nil\n}\n\n// CreateOrgRole creates a new custom role in the given organization.\nfunc (pc *Client) CreateOrgRole(\n\tctx context.Context, orgName string, req apitype.CreateRoleRequest,\n) (apitype.Role, error) {\n\tpath := fmt.Sprintf(\"/api/orgs/%s/roles\", url.PathEscape(orgName))\n\tvar resp apitype.Role\n\tif err := pc.restCall(ctx, \"POST\", path, nil, &req, &resp); err != nil {\n\t\treturn apitype.Role{}, fmt.Errorf(\"creating organization role: %w\", err)\n\t}\n\treturn resp, nil\n}\n\n// GetOrgRole fetches a single custom role by its identifier.\nfunc (pc *Client) GetOrgRole(\n\tctx context.Context, orgName, roleID string,\n) (apitype.Role, error) {\n\tpath := fmt.Sprintf(\"/api/orgs/%s/roles/%s\",\n\t\turl.PathEscape(orgName), url.PathEscape(roleID))\n\tvar resp apitype.Role\n\tif err := pc.restCall(ctx, \"GET\", path, nil, nil, &resp); err != nil {\n\t\treturn apitype.Role{}, fmt.Errorf(\"getting organization role: %w\", err)\n\t}\n\treturn resp, nil\n}\n\n// UpdateOrgRole updates an existing custom role's name, description, and details.","sourceCodeStart":1912,"sourceCodeEnd":1948,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/pkg/backend/httpstate/client/client.go#L1912-L1948","documentation":"This error wraps failures from POST /api/orgs/{org}/roles, which creates a new custom role. It is thrown by CreateOrgRole in the HTTP-state backend client when restCall fails — network errors, non-2xx status (401/403/409 for duplicates), or malformed server responses.","triggerScenarios":"Calling CreateOrgRole with an org that lacks custom-roles entitlement, a role name that already exists (409), insufficient permissions, or an invalid CreateRoleRequest payload rejected by the server.","commonSituations":"Creating a role that already exists; non-admin token; org on a plan without custom roles; submitting role definitions with disallowed characters or missing fields.","solutions":["Verify the role name doesn't already exist (list roles first).","Ensure the token has org admin/owner permissions.","Confirm the org's subscription includes custom roles.","Check the wrapped error's HTTP status: 409 → duplicate, 403 → permissions, 400 → invalid payload."],"exampleFix":"// before\nif err := pc.restCall(ctx, \"POST\", path, nil, &req, &resp); err != nil {\n\treturn apitype.Role{}, fmt.Errorf(\"creating organization role: %w\", err)\n}\n// after\nvar exists apitype.ListRolesResponse\nif err := pc.restCall(ctx, \"GET\", fmt.Sprintf(\"/api/orgs/%s/roles\", url.PathEscape(orgName)), nil, nil, &exists); err == nil {\n\tfor _, r := range exists.Roles {\n\t\tif r.Name == req.Name { return apitype.Role{}, fmt.Errorf(\"role %q already exists\", req.Name) }\n\t}\n}","handlingStrategy":"validation","validationCode":"func validRoleName(name string) bool {\n\tif name == \"\" || len(name) > 100 { return false }\n\tfor _, r := range name {\n\t\tif !(r == '-' || unicode.IsLetter(r) || unicode.IsDigit(r)) { return false }\n\t}\n\treturn true\n}\n// check existing roles before creating\nexisting, err := client.ListOrgRole(ctx, org)","typeGuard":null,"tryCatchPattern":"if err := client.CreateOrgRole(ctx, org, req); err != nil {\n\tvar apiErr *apitype.ErrorResponse\n\tif errors.As(err, &apiErr) && apiErr.Code == http.StatusConflict {\n\t\treturn fmt.Errorf(\"role %q already exists\", req.Name)\n\t}\n\treturn err\n}","preventionTips":["List existing roles first and skip creation if the name exists.","Validate role name characters/length before calling the API.","Ensure the token has org admin permissions.","Confirm the org's plan supports custom roles."],"tags":["http","pulumi-cloud","rest-client","org-roles"],"backgroundTag":"http-request-failed","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}