{"record":{"id":"2c6fe0755fcb079e","repo":"vitessio/vitess","slug":"w-cannot-create-keyspace-in-s","errorCode":null,"errorMessage":"%w: cannot create keyspace in %s","messagePattern":"%w: cannot create keyspace in (.+?)","errorType":"validation","errorClass":"ErrUnauthorized","httpStatus":null,"severity":"error","filePath":"go/vt/vtadmin/api.go","lineNumber":608,"sourceCode":"\t\treturn nil, err\n\t}\n\n\tcluster.AnnotateSpan(c, span)\n\n\treturn c.Vtctld.ConcludeTransaction(ctx, &vtctldatapb.ConcludeTransactionRequest{\n\t\tDtid: req.Dtid,\n\t})\n}\n\n// CreateKeyspace is part of the vtadminpb.VTAdminServer interface.\nfunc (api *API) CreateKeyspace(ctx context.Context, req *vtadminpb.CreateKeyspaceRequest) (*vtadminpb.CreateKeyspaceResponse, error) {\n\tspan, ctx := trace.NewSpan(ctx, \"API.CreateKeyspace\")\n\tdefer span.Finish()\n\n\tspan.Annotate(\"cluster_id\", req.ClusterId)\n\n\tif !api.authz.IsAuthorized(ctx, req.ClusterId, rbac.KeyspaceResource, rbac.CreateAction) {\n\t\treturn nil, fmt.Errorf(\"%w: cannot create keyspace in %s\", errors.ErrUnauthorized, req.ClusterId)\n\t}\n\n\tc, err := api.getClusterForRequest(req.ClusterId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tks, err := c.CreateKeyspace(ctx, req.Options)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &vtadminpb.CreateKeyspaceResponse{\n\t\tKeyspace: ks,\n\t}, nil\n}\n\n// CreateShard is part of the vtadminpb.VTAdminServer interface.","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtadmin/api.go#L590-L626","documentation":"VTAdmin's CreateKeyspace RPC returns this when the caller is not authorized for the 'create' action on the Keyspace resource in the requested cluster. The check precedes any cluster resolution and wraps errors.ErrUnauthorized. It is an RBAC policy denial at the API layer.","triggerScenarios":"Calling CreateKeyspace (POST /keyspace) where the caller's RBAC role for req.ClusterId lacks keyspace create permission.","commonSituations":"CI/service accounts with read-only roles attempting keyspace provisioning; RBAC config that only whitelists 'get' on keyspaces; typos in role resource names causing default-deny.","solutions":["Add action 'create' to the keyspace resource rules for the caller's role in the vtadmin RBAC config","Ensure the role is scoped to the correct cluster ID or uses a wildcard","Restart vtadmin and re-authenticate"],"exampleFix":"// before\n  - resource: keyspace\n    actions: [get]\n// after\n  - resource: keyspace\n    actions: [get, create, delete]","handlingStrategy":"validation","validationCode":"const canCreateKeyspace = permissions.some(rule => rule.resource === 'keyspace' && (rule.actions.includes('create') || rule.actions.includes('*')) && (rule.clusters.includes(clusterId) || rule.clusters.includes('*')));\nif (!canCreateKeyspace) throw new Error('RBAC denies keyspace create in ' + clusterId);","typeGuard":"function isKeyspaceCreateDenied(err: unknown): boolean {\n  return err instanceof Error && err.message.includes('cannot create keyspace');\n}","tryCatchPattern":"try {\n  await createKeyspace(clusterId, keyspaceReq);\n} catch (err) {\n  if (String(err).includes('cannot create keyspace')) {\n    promptForElevatedRole();\n  } else {\n    throw err;\n  }\n}","preventionTips":["Use dedicated provisioning roles with keyspace create/delete for automation","Validate cluster ID against the role's scope before calling","Keep rbac config in version control and review action lists"],"tags":["rbac","authorization","vtadmin","keyspace"],"backgroundTag":"unauthorized-rbac-action","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}