rqlite/rqlite · error

snapshot sink not open

Error message

snapshot sink not open

What it means

ErrSinkNotOpen indicates that Write or Close was invoked on a FullSink that has not been successfully opened. The sink requires a valid Open (which validates the snapshot header) before bytes can be written or the install finalized.

Source

Thrown at snapshot/sink_full.go:21

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"time"

	"github.com/rqlite/rqlite/v10/db"
	"github.com/rqlite/rqlite/v10/internal/rsum"
	"github.com/rqlite/rqlite/v10/snapshot/proto"
	"github.com/rqlite/rqlite/v10/snapshot/sidecar"
)

var (
	// ErrSinkOpen indicates that the sink is already open.
	ErrSinkOpen = errors.New("snapshot sink already open")

	// ErrSinkNotOpen indicates that the sink is not open.
	ErrSinkNotOpen = errors.New("snapshot sink not open")

	// ErrUnexpectedData indicates that the caller wrote more bytes than expected.
	ErrUnexpectedData = errors.New("no more data expected")

	// ErrIncomplete indicates Close() was called before all bytes were written.
	ErrIncomplete = errors.New("snapshot install incomplete")

	// ErrHeaderInvalid indicates the header is invalid.
	ErrHeaderInvalid = errors.New("snapshot install header invalid")

	// ErrInvalidSQLiteFile indicates the installed DB file is not a valid SQLite file.
	ErrInvalidSQLiteFile = errors.New("installed DB file is not a valid SQLite file")

	// ErrInvalidWALFile indicates the installed WAL file is not a valid SQLite WAL file.
	ErrInvalidWALFile = errors.New("installed WAL file is not a valid SQLite WAL file")
)

type installPhase int

View on GitHub (pinned to 7586a4d1bd)

Solutions

  1. Check the error returned by Open before writing; only Write/Close after a successful Open.
  2. Ensure Close is called at most once, e.g. via sync.Once or a flag.
  3. If Open failed, discard the sink and create a fresh one.

Example fix

// before
sink.Write(data) // ErrSinkNotOpen
// after
if err := sink.Open(); err != nil { return err }
if _, err := sink.Write(data); err != nil { return err }
Defensive patterns

Strategy: validation

Validate before calling

// Verify Open succeeded before writing
if err := sink.Open(); err != nil {
    return fmt.Errorf("cannot write sink: %w", err)
}

Try / catch

if _, err := sink.Write(p); err != nil {
    if errors.Is(err, snapshot.ErrSinkNotOpen) {
        return fmt.Errorf("sink lifecycle bug: write before open: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling FullSink.Write or FullSink.Close before Open, after a failed Open (e.g. Open returned ErrHeaderInvalid), or after Close already ran.

Common situations: Calling Write on a zero-value/reused sink; ignoring an error from Open and proceeding to Write; double-Close in cleanup paths.

Related errors


AI-assisted analysis of rqlite/rqlite@7586a4d1bd (2026-09-03). Data as JSON: /api/errors/e46c7dfcabd75403. Report an issue: GitHub.