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

  1. Read the wrapped '%v' inner error for the exact vschema problem.
  2. Fix the keyspace vschema (vtctldclient ApplyVSchema) — validate the JSON locally first.
  3. 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

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


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