vitessio/vitess · error · ErrThrottlerNotOpen (sentinel error)

throttler not open

Error message

throttler not open

What it means

ErrThrottlerNotOpen is the sentinel error returned by the tabletserver throttler when an operation (such as a Check) is attempted before the throttler has been opened (Throttler.Open) or after it has been closed. The throttler must be initialized and opened as part of tabletserver startup before it can serve checks.

Source

Thrown at go/vt/vttablet/tabletserver/throttle/throttler.go:120

)

var throttleTabletTypes = "replica"

var (
	statsThrottlerHeartbeatRequests    = stats.NewCounter("ThrottlerHeartbeatRequests", "heartbeat requests")
	statsThrottlerProbeRecentlyChecked = stats.NewCounter("ThrottlerProbeRecentlyChecked", "probe recently checked")
)

func init() {
	servenv.OnParseFor("vtcombo", registerThrottlerFlags)
	servenv.OnParseFor("vttablet", registerThrottlerFlags)
}

func registerThrottlerFlags(fs *pflag.FlagSet) {
	utils.SetFlagStringVar(fs, &throttleTabletTypes, "throttle-tablet-types", throttleTabletTypes, "Comma separated VTTablet types to be considered by the throttler. default: 'replica'. example: 'replica,rdonly'. 'replica' always implicitly included")
}

var ErrThrottlerNotOpen = errors.New("throttler not open")

// throttlerTopoService represents the functionality we expect from a TopoServer, abstracted so that
// it can be mocked in unit tests
type throttlerTopoService interface {
	GetTablet(ctx context.Context, alias *topodatapb.TabletAlias) (*topo.TabletInfo, error)
	FindAllTabletAliasesInShard(ctx context.Context, keyspace, shard string) ([]*topodatapb.TabletAlias, error)
	GetSrvKeyspace(ctx context.Context, cell, keyspace string) (*topodatapb.SrvKeyspace, error)
}

// Throttler is the main entity in the throttling mechanism. This service runs, probes, collects data,
// aggregates, reads inventory, provides information, etc.
type Throttler struct {
	keyspace    string
	shard       string
	tabletAlias *topodatapb.TabletAlias
	tabletInfo  atomic.Pointer[topo.TabletInfo]

	check     *ThrottlerCheck

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Ensure the tabletserver (and thus throttler.Open) has finished initialization before issuing throttler checks.
  2. Retry the check after a short delay — this is typically a transient startup/shutdown race.
  3. In tests, call throttler.Open() and defer throttler.Close() around usage.
  4. If persistent, check vttablet logs for throttler initialization failures (e.g. topo errors) preventing Open.

Example fix

// before
res, err := throttleApp.Check(ctx, flags) // may run before throttler opened
// after
if err := th.Open(ctx); err != nil { return err }
res, err := throttleApp.Check(ctx, flags)
Defensive patterns

Strategy: retry

Type guard

func (t *Throttler) IsOpen() bool { return atomic.LoadInt32(&t.isOpen) > 0 }

Try / catch

if errors.Is(err, throttle.ErrThrottlerNotOpen) {
  time.AfterFunc(time.Second, func() { retryCheck(ctx) })
  return
}

Prevention

When it happens

Trigger: Calling throttle.Check / CheckApp before tabletserver.Init completes, or after tabletserver closes the throttler on shutdown; unit tests instantiating a Throttler struct without calling Open.

Common situations: Health-check requests racing tablet startup; vttablet shutting down while VReplication or a custom caller still issues throttler checks; tests constructing throttler by hand.

Related errors


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