vitessio/vitess · error · ErrUnauthorized

%w: cannot create keyspace in %s

Error message

%w: cannot create keyspace in %s

What it means

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.

Source

Thrown at go/vt/vtadmin/api.go:608

		return nil, err
	}

	cluster.AnnotateSpan(c, span)

	return c.Vtctld.ConcludeTransaction(ctx, &vtctldatapb.ConcludeTransactionRequest{
		Dtid: req.Dtid,
	})
}

// CreateKeyspace is part of the vtadminpb.VTAdminServer interface.
func (api *API) CreateKeyspace(ctx context.Context, req *vtadminpb.CreateKeyspaceRequest) (*vtadminpb.CreateKeyspaceResponse, error) {
	span, ctx := trace.NewSpan(ctx, "API.CreateKeyspace")
	defer span.Finish()

	span.Annotate("cluster_id", req.ClusterId)

	if !api.authz.IsAuthorized(ctx, req.ClusterId, rbac.KeyspaceResource, rbac.CreateAction) {
		return nil, fmt.Errorf("%w: cannot create keyspace in %s", errors.ErrUnauthorized, req.ClusterId)
	}

	c, err := api.getClusterForRequest(req.ClusterId)
	if err != nil {
		return nil, err
	}

	ks, err := c.CreateKeyspace(ctx, req.Options)
	if err != nil {
		return nil, err
	}

	return &vtadminpb.CreateKeyspaceResponse{
		Keyspace: ks,
	}, nil
}

// CreateShard is part of the vtadminpb.VTAdminServer interface.

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Add action 'create' to the keyspace resource rules for the caller's role in the vtadmin RBAC config
  2. Ensure the role is scoped to the correct cluster ID or uses a wildcard
  3. Restart vtadmin and re-authenticate

Example fix

// before
  - resource: keyspace
    actions: [get]
// after
  - resource: keyspace
    actions: [get, create, delete]
Defensive patterns

Strategy: validation

Validate before calling

const canCreateKeyspace = permissions.some(rule => rule.resource === 'keyspace' && (rule.actions.includes('create') || rule.actions.includes('*')) && (rule.clusters.includes(clusterId) || rule.clusters.includes('*')));
if (!canCreateKeyspace) throw new Error('RBAC denies keyspace create in ' + clusterId);

Type guard

function isKeyspaceCreateDenied(err: unknown): boolean {
  return err instanceof Error && err.message.includes('cannot create keyspace');
}

Try / catch

try {
  await createKeyspace(clusterId, keyspaceReq);
} catch (err) {
  if (String(err).includes('cannot create keyspace')) {
    promptForElevatedRole();
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling CreateKeyspace (POST /keyspace) where the caller's RBAC role for req.ClusterId lacks keyspace create permission.

Common situations: 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.

Related errors


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