vitessio/vitess · error

VStreamer is not open

Error message

VStreamer is not open

What it means

The VStreamer Engine rejects a new UVStream request when its atomic isOpen flag is 0, i.e. the VStreamer engine has not been opened (Engine.Open) or was already closed. Streams can only be created while the engine is open, so the request fails with "VStreamer is not open".

Source

Thrown at go/vt/vttablet/tabletserver/vstreamer/engine.go:255

// Stream starts a new stream.
// This streams events from the binary logs
func (vse *Engine) Stream(ctx context.Context, startPos string, tablePKs []*binlogdatapb.TableLastPK,
	filter *binlogdatapb.Filter, throttlerApp throttlerapp.Name,
	send func([]*binlogdatapb.VEvent) error, options *binlogdatapb.VStreamOptions,
) error {
	if err := vse.validateBinlogRowImage(ctx, vse.se.GetDBConnector()); err != nil {
		return err
	}

	// Ensure vschema is initialized and the watcher is started.
	// Starting of the watcher has to be delayed till the first call to Stream
	// because this overhead should be incurred only if someone uses this feature.
	vse.watcherOnce.Do(vse.setWatch)

	// Create stream and add it to the map.
	streamer, idx, err := func() (*uvstreamer, int, error) {
		if atomic.LoadInt32(&vse.isOpen) == 0 {
			return nil, 0, errors.New("VStreamer is not open")
		}
		vse.mu.Lock()
		defer vse.mu.Unlock()
		streamer := newUVStreamer(ctx, vse, vse.env.Config().DB.FilteredWithDB(), vse.se, startPos, tablePKs,
			filter, vse.lvschema, throttlerApp, send, options)
		idx := vse.streamIdx
		vse.streamers[idx] = streamer
		vse.streamIdx++
		// Now that we've added the stream, increment wg.
		// This must be done before releasing the lock.
		vse.wg.Add(1)
		return streamer, idx, nil
	}()
	if err != nil {
		return err
	}

	// Remove stream from map and decrement wg when it ends.

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Wait for the tablet to fully start (VStreamer engine opened) and retry the VStream request.
  2. Check vttablet logs/errors during startup — the engine may have failed to open due to topo or DB issues.
  3. Point the VReplication workflow at a tablet that is up and serving, not one mid-restart.
  4. In tests, call vse.Open() before streaming and defer vse.Close().

Example fix

// before
err := vstreamerEngine.UVStream(ctx, startPos, nil, filter, app, send, options) // engine closed
// after
if err := vstreamerEngine.Open(ctx); err != nil { return err }
err := vstreamerEngine.UVStream(ctx, startPos, nil, filter, app, send, options)
Defensive patterns

Strategy: retry

Validate before calling

if !vse.IsOpen() { return errors.New("VStreamer engine not open; retry after tablet startup") }

Type guard

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

Try / catch

if err := engine.UVStream(...); err != nil && strings.Contains(err.Error(), "VStreamer is not open") {
  // retry with backoff after tablet readiness
}

Prevention

When it happens

Trigger: Calling Engine.UVStream (via VStream API / VReplication workflow) before tabletserver finishes opening the VStreamer engine, or after Close during shutdown.

Common situations: VReplication workflow start racing vttablet startup or shutdown; move-tables/resume operations hitting a tablet that is being restarted; unit tests using an unopened Engine.

Related errors


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