vitessio/vitess · error · ErrUnauthorized
%w: cannot retry schema migration in %s
Error message
%w: cannot retry schema migration in %s
What it means
VTAdmin's RetrySchemaMigration RPC returns this when RBAC denies the retry action on the schema_migration resource in the target cluster. It wraps errors.ErrUnauthorized for errors.Is matching. It is returned before contacting vtctld.
Source
Thrown at go/vt/vtadmin/api.go:2324
})
if err != nil {
return nil, err
}
return &vtadminpb.ReloadSchemaShardResponse{
Events: res.Events,
}, nil
}
// RetrySchemaMigration is part of the vtadminpb.VTAdminServer interface.
func (api *API) RetrySchemaMigration(ctx context.Context, req *vtadminpb.RetrySchemaMigrationRequest) (*vtctldatapb.RetrySchemaMigrationResponse, error) {
span, ctx := trace.NewSpan(ctx, "API.RetrySchemaMigration")
defer span.Finish()
span.Annotate("cluster_id", req.ClusterId)
if !api.authz.IsAuthorized(ctx, req.ClusterId, rbac.SchemaMigrationResource, rbac.RetryAction) {
return nil, fmt.Errorf("%w: cannot retry schema migration in %s", errors.ErrUnauthorized, req.ClusterId)
}
c, err := api.getClusterForRequest(req.ClusterId)
if err != nil {
return nil, err
}
return c.RetrySchemaMigration(ctx, req.Request)
}
// RunHealthCheck is part of the vtadminpb.VTAdminServer interface.
func (api *API) RunHealthCheck(ctx context.Context, req *vtadminpb.RunHealthCheckRequest) (*vtadminpb.RunHealthCheckResponse, error) {
span, ctx := trace.NewSpan(ctx, "API.RunHealthCheck")
defer span.Finish()
tablet, c, err := api.getTabletForAction(ctx, span, rbac.GetAction, req.Alias, req.ClusterIds)
if err != nil {
return nil, errView on GitHub (pinned to 01a25a7d17)
Solutions
- Grant the retry action on the schema_migration resource to the caller's RBAC role
- Confirm the cluster_id in the request matches the rules configured for that role
- Verify authenticated identity resolution (auth headers/Impersonation rules) maps to the intended subject
Example fix
// before - resource: schema_migration actions: [get] // after - resource: schema_migration actions: [get, retry]
Defensive patterns
Strategy: validation
Validate before calling
func canRetrySchemaMigration(role string) bool {
allowed := map[string]bool{"admin": true, "operator": true}
return allowed[role]
} Type guard
func isUnauthorizedErr(err error) bool {
return err != nil && errors.Is(err, apierrors.ErrUnauthorized)
} Try / catch
resp, err := client.RetrySchemaMigration(ctx, req)
if err != nil {
if errors.Is(err, apierrors.ErrUnauthorized) {
return fmt.Errorf("insufficient RBAC permissions to retry schema migration in %s", req.ClusterId)
}
return err
} Prevention
- Grant schema_migration retry alongside create in operator roles so migration workflows are fully operable
- Verify the caller identity maps to the expected RBAC subject
- Test retry permissions for each cluster ID in staging
When it happens
Trigger: Calling API.RetrySchemaMigration when api.authz.IsAuthorized(ctx, req.ClusterId, rbac.SchemaMigrationResource, rbac.RetryAction) returns false.
Common situations: RBAC role has get/list on schema migrations but not retry; users trying to retry a failed migration with a viewer role; misconfigured subject mapping falling back to a restricted role.
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 launch schema migration in %s
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/e27d9e750e9ac49b.
Report an issue: GitHub.