vitessio/vitess · error · ErrUnauthorized
%w: cannot launch schema migration in %s
Error message
%w: cannot launch schema migration in %s
What it means
API.LaunchSchemaMigration enforces RBAC before doing any work: if the caller's credentials are not authorized for the LaunchSchemaMigration action on the SchemaMigrationResource in the requested cluster, it returns errors.ErrUnauthorized wrapped with this message. It is a sentinel-wrapped error, testable with errors.Is, and thrown before any cluster lookup or vtctld call.
Source
Thrown at go/vt/vtadmin/api.go:2014
if rec.HasErrors() {
return nil, rec.Error()
}
return &vtadminpb.GetWorkflowsResponse{
WorkflowsByCluster: results,
}, nil
}
// LaunchSchemaMigration is part of the vtadminpb.VTAdminServer interface.
func (api *API) LaunchSchemaMigration(ctx context.Context, req *vtadminpb.LaunchSchemaMigrationRequest) (*vtctldatapb.LaunchSchemaMigrationResponse, error) {
span, ctx := trace.NewSpan(ctx, "API.LaunchSchemaMigration")
defer span.Finish()
span.Annotate("cluster_id", req.ClusterId)
if !api.authz.IsAuthorized(ctx, req.ClusterId, rbac.SchemaMigrationResource, rbac.LaunchSchemaMigrationAction) {
return nil, fmt.Errorf("%w: cannot launch schema migration in %s", errors.ErrUnauthorized, req.ClusterId)
}
c, err := api.getClusterForRequest(req.ClusterId)
if err != nil {
return nil, err
}
return c.LaunchSchemaMigration(ctx, req.Request)
}
// MaterializeCreate is part of the vtadminpb.VTAdminServer interface.
func (api *API) MaterializeCreate(ctx context.Context, req *vtadminpb.MaterializeCreateRequest) (*vtctldatapb.MaterializeCreateResponse, error) {
span, ctx := trace.NewSpan(ctx, "API.MaterializeCreate")
defer span.Finish()
span.Annotate("cluster_id", req.ClusterId)
if !api.authz.IsAuthorized(ctx, req.ClusterId, rbac.WorkflowResource, rbac.CreateAction) {View on GitHub (pinned to 01a25a7d17)
Solutions
- Check the RBAC config (authz rules) for a rule granting rbac.LaunchSchemaMigrationAction on SchemaMigrationResource for the caller's identity in this cluster
- Verify the client is sending valid credentials/headers recognized by vtadmin's auth middleware
- Fix cluster ID in the request if the rule is cluster-scoped and the ID mismatches
- Reload/restart vtadmin after editing the authorization config
Example fix
// rbac.yaml before: read-only user
rules:
- resource: "SchemaMigration"
actions: ["get"]
// after: grant launch action
rules:
- resource: "SchemaMigration"
actions: ["get", "launch", "cancel", "cleanup", "complete"] Defensive patterns
Strategy: validation
Validate before calling
// Go: pre-check authorization client-side
if !userRoles.Can("launch", "SchemaMigration", clusterID) {
return fmt.Errorf("user lacks launch schema migration permission in %s", clusterID)
} Type guard
func isUnauthorized(err error) bool {
return errors.Is(err, vtadminerrors.ErrUnauthorized)
} Try / catch
resp, err := client.LaunchSchemaMigration(ctx, req)
if err != nil {
if isUnauthorized(err) {
// surface permission-denied UI, don't retry
}
return err
} Prevention
- Grant SchemaMigration launch action to operator roles in RBAC config
- Send auth credentials/headers on every vtadmin request
- Test RBAC rules with a least-privilege user before rollout
- Keep cluster-scoped rules aligned with actual cluster IDs
When it happens
Trigger: Calling LaunchSchemaMigration with credentials (from the vtadmin auth context — e.g. missing/invalid bearer token, or identity not matching an RBAC rule) that lack permission for schema-migration launch in req.ClusterId.
Common situations: User authenticated but their role's RBAC policy lacks launch_schema_migration; cluster-scoped rule that doesn't cover this cluster ID; authz config file not reloaded after adding permissions; missing auth headers from an API client.
Related errors
- %w: cannot create schema migration in %s
- %w: cannot cancel schema migration in %s
- %w: cannot cleanup schema migration in %s
- %w: cannot complete schema migration in %s
- %w: cannot retry schema migration in %s
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/e417ae274ca2865a.
Report an issue: GitHub.