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

  1. Check the RBAC config (authz rules) for a rule granting rbac.LaunchSchemaMigrationAction on SchemaMigrationResource for the caller's identity in this cluster
  2. Verify the client is sending valid credentials/headers recognized by vtadmin's auth middleware
  3. Fix cluster ID in the request if the rule is cluster-scoped and the ID mismatches
  4. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/e417ae274ca2865a. Report an issue: GitHub.