vitessio/vitess · error
no tablet picker configured for %s/%s
Error message
no tablet picker configured for %s/%s
What it means
pickSourceTablet needs a TabletPicker (ct.tpTs) to find a healthy serving tablet in the source keyspace/shard. If no tablet picker was configured for the controller (and the source is not an external MySQL), it returns `no tablet picker configured for <keyspace>/<shard>`.
Source
Thrown at go/vt/vttablet/tabletmanager/vreplication/controller.go:384
Time: time.Now(),
Message: message,
})
query := fmt.Sprintf("update _vt.vreplication set message=%v where id=%v", encodeString(binlogplayer.MessageTruncate(message)), ct.id)
if _, err := dbClient.ExecuteFetch(query, 1); err != nil {
return fmt.Errorf("could not set message: %v: %v", query, err)
}
return nil
}
// pickSourceTablet picks a healthy serving tablet to source for
// the vreplication stream. If the source is marked as external, it
// returns nil.
func (ct *controller) pickSourceTablet(ctx context.Context, dbClient binlogplayer.DBClient) (*topodatapb.Tablet, error) {
if ct.source.GetExternalMysql() != "" {
return nil, nil
}
if ct.tpTs == nil {
return nil, fmt.Errorf("no tablet picker configured for %s/%s", ct.source.Keyspace, ct.source.Shard)
}
log.Info(fmt.Sprintf("%s trying to find an eligible source tablet in %s/%s", ct.logPrefix(), ct.source.Keyspace, ct.source.Shard))
tablet, err := ct.pickSourceTabletWithIgnoreList(ctx, dbClient)
// If we failed to find any tablet and we specified an ignore list, then clear the ignore list so that
// we can try tablets that were previously ignored(since some state may have changed since the last attempt).
if err != nil && len(ct.ignoreTablets) > 0 {
log.Info(fmt.Sprintf("%s clearing ignore list of %d tablets and retrying tablet picker",
ct.logPrefix(), len(ct.ignoreTablets)))
ct.ignoreTablets = nil
tablet, err = ct.pickSourceTabletWithIgnoreList(ctx, dbClient)
}
if err != nil {
return tablet, err
}
ct.setMessage(dbClient, "Picked source tablet: "+tablet.Alias.String())
log.Info(fmt.Sprintf("%s found eligible source tablet %s", ct.logPrefix(), tablet.Alias.String()))
ct.sourceTablet.Store(tablet.Alias)View on GitHub (pinned to 01a25a7d17)
Solutions
- Verify the source keyspace and shard exist and have serving tablets in the topology (`vtctldclient GetTablets`).
- Check the vttablet flags for cell / topo implementation are correct.
- If the source is truly external MySQL, ensure ExternalMysql is set on the stream source so the picker isn't required.
- Re-create the workflow with correct source keyspace/shard.
Example fix
// before (stream created against wrong keyspace) sourceKeyspace: "commerce_old" // does not exist in topo // after vtctldclient MoveTables --target-keyspace commerce --tables t1 create commerce_old
Defensive patterns
Strategy: validation
Validate before calling
// Verify serving tablets exist before creating a workflow: vtctldclient GetTablets --keyspace commerce --shard 0 | grep -i serving # or in Go, check the topo for source keyspace/shard before constructing the controller
Try / catch
tablet, err := ct.pickSourceTablet(ctx, dbClient)
if err != nil && strings.Contains(err.Error(), "no tablet picker configured") {
return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "source %s/%s not usable: %w", ks, shard, err)
} Prevention
- Confirm source keyspace/shard exist in topology before MoveTables/Reshard.
- Start vttablet with correct --cell and topo flags so a picker can be constructed.
- For external MySQL sources, ensure ExternalMysql is properly recorded on the stream.
When it happens
Trigger: A vreplication stream whose source.Keyspace/Shard is set, ExternalMysql is empty, but the controller was created without a tablet picker timestamp source (ct.tpTs == nil) — typically when the local cell has no topology service or the controller was constructed in a code path that skips picker setup.
Common situations: Misconfigured MoveTables/Reshard workflow where the source keyspace/shard doesn't exist in the topology; vttablet started without proper cell/topo flags; external MySQL handling changed between versions so the external check no longer short-circuits.
Related errors
- could not get RoutingRules
- no primary found for shard
- stream needs a position or a table to copy
- partial row image encountered: ensure binlog_row_image is se
- failed to instantiate throttler: %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/f5d6a55db84fbbdd.
Report an issue: GitHub.