vitessio/vitess · warning
VStreamer is not open
Error message
VStreamer is not open
What it means
tableStreamer.newRowStreamer re-checks the VStreamer engine's isOpen flag before spawning each per-table row streamer. Because table streaming is long-lived, the engine may have been closed (or not yet fully open) between stream creation and this per-row-stream creation; when isOpen is 0 it returns "VStreamer is not open".
Source
Thrown at go/vt/vttablet/tabletserver/vstreamer/tablestreamer.go:157
log.Info(fmt.Sprintf("Found %d tables to stream: %s", len(ts.tables), strings.Join(ts.tables, ", ")))
for _, tableName := range ts.tables {
log.Info("Streaming table " + tableName)
if err := ts.streamTable(ts.ctx, tableName); err != nil {
log.Error(fmt.Sprintf("Streaming table %s failed: %v", tableName, err))
return err
}
log.Info("Finished streaming table " + tableName)
}
log.Info(fmt.Sprintf("Finished streaming %d tables", len(ts.tables)))
return nil
}
func (ts *tableStreamer) newRowStreamer(ctx context.Context, query string, lastpk []sqltypes.Value,
send func(*binlogdatapb.VStreamRowsResponse) error,
) (*rowStreamer, func(), error) {
vse := ts.vse
if atomic.LoadInt32(&vse.isOpen) == 0 {
return nil, nil, errors.New("VStreamer is not open")
}
vse.mu.Lock()
defer vse.mu.Unlock()
rowStreamer := newRowStreamer(ctx, vse.env.Config().DB.FilteredWithDB(), vse.se, query, lastpk, vse.lvschema,
send, vse, RowStreamerModeAllTables, ts.snapshotConn, ts.options)
idx := vse.streamIdx
vse.rowStreamers[idx] = rowStreamer
vse.streamIdx++
// Now that we've added the stream, increment wg.
// This must be done before releasing the lock.
vse.wg.Add(1)
// Remove stream from map and decrement wg when it ends.
cancel := func() {
vse.mu.Lock()
defer vse.mu.Unlock()View on GitHub (pinned to 01a25a7d17)
Solutions
- Treat as a benign shutdown signal: the stream should be cancelled/restarted — VReplication workflows will retry automatically.
- If seen outside shutdowns, verify the tabletserver/VStreamer engine stayed open (check startup/shutdown logs).
- Retry the VStream/workflow once the tablet is fully healthy.
Example fix
// before
rs, cancel, err := ts.newRowStreamer(ctx, query, lastpk, send) // fails mid-shutdown
// after
if err != nil && err.Error() == "VStreamer is not open" { return gracefulStop() } // handle engine shutdown Defensive patterns
Strategy: try-catch
Type guard
func engineShutdownErr(err error) bool { return err != nil && strings.Contains(err.Error(), "VStreamer is not open") } Try / catch
rs, cancel, err := ts.newRowStreamer(ctx, query, lastpk, send)
if engineShutdownErr(err) {
log.Info("VStreamer engine closed mid-stream; stopping table stream gracefully")
return nil, nil, nil
} Prevention
- Expect this during vttablet shutdown; ensure VReplication retry logic handles it.
- Drain/cancel VReplication workflows before planned restarts.
- Monitor tablet restarts correlated with VReplication error rates.
When it happens
Trigger: A running tableStreamer (streamTable / multi-table copy) calling newRowStreamer after Engine.Close, or before the engine finished opening; recursively invoked as newRowStreamer creates child row streamers.
Common situations: vttablet shutdown or tabletserver restart while a VReplication copy phase is actively streaming tables; cancelling VReplication workflows racing stream creation.
Related errors
- VStreamer is not open
- both atomic copy and partial mode cannot be specified for th
- invalid workflow
- multiple source keyspaces for a single workflow
- multiple target keyspaces for a single workflow
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/f5f0def82a96faeb.
Report an issue: GitHub.