{"record":{"id":"caa77c34e9eb1f69","repo":"vitessio/vitess","slug":"w-cannot-cancel-schema-migration-in-s","errorCode":null,"errorMessage":"%w: cannot cancel schema migration in %s","messagePattern":"%w: cannot cancel schema migration in (.+?)","errorType":"validation","errorClass":"ErrUnauthorized","httpStatus":null,"severity":"error","filePath":"go/vt/vtadmin/api.go","lineNumber":530,"sourceCode":"\tif req.CallerId != \"\" {\n\t\treq.Request.CallerId = &vtrpcpb.CallerID{Principal: req.CallerId}\n\t}\n\n\t// Set the default wait replicas timeout.\n\treq.Request.WaitReplicasTimeout = protoutil.DurationToProto(grpcvtctldserver.DefaultWaitReplicasTimeout)\n\n\treturn c.ApplySchema(ctx, req.Request)\n}\n\n// CancelSchemaMigration is part of the vtadminpb.VTAdminServer interface.\nfunc (api *API) CancelSchemaMigration(ctx context.Context, req *vtadminpb.CancelSchemaMigrationRequest) (*vtctldatapb.CancelSchemaMigrationResponse, error) {\n\tspan, ctx := trace.NewSpan(ctx, \"API.CancelSchemaMigration\")\n\tdefer span.Finish()\n\n\tspan.Annotate(\"cluster_id\", req.ClusterId)\n\n\tif !api.authz.IsAuthorized(ctx, req.ClusterId, rbac.SchemaMigrationResource, rbac.CancelAction) {\n\t\treturn nil, fmt.Errorf(\"%w: cannot cancel schema migration 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\treturn c.CancelSchemaMigration(ctx, req.Request)\n}\n\n// CleanupSchemaMigration is part of the vtadminpb.VTAdminServer interface.\nfunc (api *API) CleanupSchemaMigration(ctx context.Context, req *vtadminpb.CleanupSchemaMigrationRequest) (*vtctldatapb.CleanupSchemaMigrationResponse, error) {\n\tspan, ctx := trace.NewSpan(ctx, \"API.CleanupSchemaMigration\")\n\tdefer span.Finish()\n\n\tspan.Annotate(\"cluster_id\", req.ClusterId)\n\n\tif !api.authz.IsAuthorized(ctx, req.ClusterId, rbac.SchemaMigrationResource, rbac.CleanupSchemaMigrationAction) {","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtadmin/api.go#L512-L548","documentation":"VTAdmin's CancelSchemaMigration RPC returns this when the caller is not authorized with the 'cancel' action on the SchemaMigration resource for the given cluster. The check runs before any cluster lookup, wrapping errors.ErrUnauthorized. It indicates RBAC policy denial, not a migration failure.","triggerScenarios":"Calling CancelSchemaMigration (DELETE /schema/cancel) for a cluster where the caller's role omits the cancel action on schema-migration resources.","commonSituations":"Operators with create-only schema permissions trying to cancel an in-flight migration; RBAC config that enumerates actions narrowly (get, create) but not cancel; wrong cluster ID mapped to a restrictive role.","solutions":["Add action 'cancel' (or use a wildcard) to the caller's role for the schema-migration resource in the RBAC config","Confirm the request's cluster ID is the one the permissive role covers","Reload/restart vtadmin with the updated RBAC config"],"exampleFix":"// before\n  - resource: schema-migration\n    actions: [get, create]\n// after\n  - resource: schema-migration\n    actions: [get, create, cancel, complete, cleanup]","handlingStrategy":"validation","validationCode":"const canCancel = permissions.some(rule => rule.resource === 'schema-migration' && (rule.actions.includes('cancel') || rule.actions.includes('*')) && (rule.clusters.includes(clusterId) || rule.clusters.includes('*')));\nif (!canCancel) console.warn('RBAC will deny CancelSchemaMigration for cluster ' + clusterId);","typeGuard":"function isCancelUnauthorized(err: unknown): boolean {\n  return err instanceof Error && err.message.includes('cannot cancel schema migration');\n}","tryCatchPattern":"try {\n  await cancelSchemaMigration(clusterId, uuid);\n} catch (err) {\n  if (String(err).includes('cannot cancel schema migration')) {\n    requestRbacGrant(['cancel']);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Include cancel/complete/cleanup alongside create when granting schema-migration permissions","Verify per-cluster role scoping in rbac config","Test permission changes in a staging cluster first"],"tags":["rbac","authorization","vtadmin","schema-migration"],"backgroundTag":"unauthorized-rbac-action","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}