vitessio/vitess · warning · ErrAmbiguousSchema

%w: %d schemas found with table named %s

Error message

%w: %d schemas found with table named %s

What it means

VTAdmin's FindSchema RPC searches all clusters for schemas containing the requested table; when the table is found in more than one distinct schema it refuses to guess and returns errors.ErrAmbiguousSchema wrapped with the match count and table name. This protects callers from silently acting on the wrong keyspace/table definition. Exactly one match returns that schema; zero matches are handled earlier in the switch.

Source

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

		}(c)
	}

	wg.Wait()

	if rec.HasErrors() {
		return nil, rec.Error()
	}

	switch len(results) {
	case 0:
		return nil, &errors.NoSuchSchema{
			Clusters: clusterIDs,
			Table:    req.Table,
		}
	case 1:
		return results[0], nil
	default:
		return nil, fmt.Errorf("%w: %d schemas found with table named %s", errors.ErrAmbiguousSchema, len(results), req.Table)
	}
}

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

	clusters, _ := api.getClustersForRequest(req.ClusterIds)

	var (
		m       sync.Mutex
		wg      sync.WaitGroup
		rec     concurrency.AllErrorRecorder
		backups []*vtadminpb.ClusterBackup
	)

	if req.RequestOptions == nil {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Narrow the request to a single cluster by setting Clusters in the FindSchema request (or the cluster_ids query param)
  2. Use a more specific table name, including keyspace qualification if the API path supports it
  3. If the ambiguity is a real duplicate, pick the intended cluster and query its schema directly via GetSchema

Example fix

// before
GET /api/schema?table=users
// after
GET /api/schema?table=users&cluster_ids=commerce
Defensive patterns

Strategy: try-catch

Validate before calling

const matches = await Promise.all(clusterIds.map(c => getSchema(c, table).catch(() => null)));
const found = matches.filter(Boolean);
if (found.length > 1) {
  throw new Error('table ' + table + ' exists in ' + found.length + ' clusters; narrow with cluster_ids');
}

Type guard

function isAmbiguousSchema(err: unknown): boolean {
  return err instanceof Error && err.message.includes('schemas found with table named');
}

Try / catch

try {
  schema = await findSchema(table, clusterIds);
} catch (err) {
  if (isAmbiguousSchema(err)) {
    const n = parseInt(err.message, 10);
    schema = await findSchema(table, [preferredCluster]);
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling FindSchema (GET /schema?table=users) where the table name exists in schemas of 2+ clusters (per the request's cluster filter) so the default case (len(results) > 1) is hit.

Common situations: Multi-cluster setups where the same table name (e.g. 'users') is deployed in several keyspaces/clusters; calling without narrowing Clusters in the request; shared table naming conventions across environments.

Related errors


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