vitessio/vitess · error
cannot build vschema for keyspace %v: %v
Error message
cannot build vschema for keyspace %v: %v
What it means
After finding the keyspace entry in SrvVSchema, the resolver builds a full keyspace schema via vindexes.BuildKeyspaceSchema. If the vschema definition is invalid (bad vindex types, malformed tables), streaming fails with the underlying build error wrapped.
Source
Thrown at go/vt/binlog/keyspace_id_resolver.go:67
// keyspaceIDResolverFactory for the provided keyspace and cell.
func newKeyspaceIDResolverFactory(ctx context.Context, ts *topo.Server, keyspace string, cell string, parser *sqlparser.Parser) (keyspaceIDResolverFactory, error) {
return newKeyspaceIDResolverFactoryV3(ctx, ts, keyspace, cell, parser)
}
// newKeyspaceIDResolverFactoryV3 finds the SrvVSchema in the cell,
// gets the keyspace part, and uses it to find the column name.
func newKeyspaceIDResolverFactoryV3(ctx context.Context, ts *topo.Server, keyspace string, cell string, parser *sqlparser.Parser) (keyspaceIDResolverFactory, error) {
srvVSchema, err := ts.GetSrvVSchema(ctx, cell)
if err != nil {
return nil, err
}
kschema, ok := srvVSchema.Keyspaces[keyspace]
if !ok {
return nil, fmt.Errorf("SrvVSchema has no entry for keyspace %v", keyspace)
}
keyspaceSchema, err := vindexes.BuildKeyspaceSchema(kschema, keyspace, parser)
if err != nil {
return nil, fmt.Errorf("cannot build vschema for keyspace %v: %v", keyspace, err)
}
return func(table *schema.Table) (int, keyspaceIDResolver, error) {
// Find the v3 schema.
tableSchema, ok := keyspaceSchema.Tables[table.Name.String()]
if !ok {
return -1, nil, fmt.Errorf("no vschema definition for table %v", table.Name)
}
// use the lowest cost unique vindex as the sharding key
colVindex, err := vindexes.FindVindexForSharding(table.Name.String(), tableSchema.ColumnVindexes)
if err != nil {
return -1, nil, err
}
// TODO @rafael - when rewriting the mapping function, this will need to change.
// for now it's safe to assume the sharding key will be always on index 0.
shardingColumnName := colVindex.Columns[0].String()
for i, col := range table.Fields {View on GitHub (pinned to 01a25a7d17)
Solutions
- Read the wrapped '%v' inner error for the exact vschema problem.
- Fix the keyspace vschema (vtctldclient ApplyVSchema) — validate the JSON locally first.
- Rebuild SrvVSchema (RebuildKeyspaceGraph) after correcting, then retry the stream.
Example fix
// before (invalid vindex type)
{"vindexes":{"h":{"type":"hashhh"}}}
// after
{"vindexes":{"h":{"type":"hash"}}} Defensive patterns
Strategy: validation
Validate before calling
var vs map[string]any
if err := json.Unmarshal(vschemaJSON, &vs); err != nil {
return fmt.Errorf("invalid vschema JSON: %w", err)
}
// validate vindex types exist before applying
for name, vi := range vs["vindexes"].(map[string]any) {
t := vi.(map[string]any)["type"]
if !knownVindexTypes[t.(string)] {
return fmt.Errorf("unknown vindex type %s for %s", t, name)
}
} Try / catch
if err := updateStream.StreamKeyRange(ctx, ...); err != nil {
if strings.Contains(err.Error(), "cannot build vschema") {
log.Error("fix vschema via vtctldclient ApplyVSchema", slog.Any("error", err))
}
return err
} Prevention
- Validate vschema JSON (vtctldclient ApplyVSchema does server-side validation) before streaming.
- Keep vindex type names correct; check the vindexes package list.
- Re-run RebuildKeyspaceGraph after every ApplyVSchema.
When it happens
Trigger: StreamKeyRange on a keyspace whose SrvVSchema entry has invalid vindex definitions or malformed table/vindex configuration.
Common situations: Typo in vindex type name in the vschema JSON; vindex referencing a non-existent column-owner table; incompatible vschema after a migration.
Related errors
- one or two tables must be specified
- at least one table must be specified
- vindex is in write-only mode
- vindex has no owner
- no sharded vschema was provided, so you will need to update
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/dba26d28a57cc8ad.
Report an issue: GitHub.