{"record":{"id":"e46c7dfcabd75403","repo":"rqlite/rqlite","slug":"snapshot-sink-not-open","errorCode":null,"errorMessage":"snapshot sink not open","messagePattern":"snapshot sink not open","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"snapshot/sink_full.go","lineNumber":21,"sourceCode":"import (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/rqlite/rqlite/v10/db\"\n\t\"github.com/rqlite/rqlite/v10/internal/rsum\"\n\t\"github.com/rqlite/rqlite/v10/snapshot/proto\"\n\t\"github.com/rqlite/rqlite/v10/snapshot/sidecar\"\n)\n\nvar (\n\t// ErrSinkOpen indicates that the sink is already open.\n\tErrSinkOpen = errors.New(\"snapshot sink already open\")\n\n\t// ErrSinkNotOpen indicates that the sink is not open.\n\tErrSinkNotOpen = errors.New(\"snapshot sink not open\")\n\n\t// ErrUnexpectedData indicates that the caller wrote more bytes than expected.\n\tErrUnexpectedData = errors.New(\"no more data expected\")\n\n\t// ErrIncomplete indicates Close() was called before all bytes were written.\n\tErrIncomplete = errors.New(\"snapshot install incomplete\")\n\n\t// ErrHeaderInvalid indicates the header is invalid.\n\tErrHeaderInvalid = errors.New(\"snapshot install header invalid\")\n\n\t// ErrInvalidSQLiteFile indicates the installed DB file is not a valid SQLite file.\n\tErrInvalidSQLiteFile = errors.New(\"installed DB file is not a valid SQLite file\")\n\n\t// ErrInvalidWALFile indicates the installed WAL file is not a valid SQLite WAL file.\n\tErrInvalidWALFile = errors.New(\"installed WAL file is not a valid SQLite WAL file\")\n)\n\ntype installPhase int","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/rqlite/rqlite/blob/7586a4d1bdbd9a5a80021664c5a863cd850adb60/snapshot/sink_full.go#L3-L39","documentation":"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.","triggerScenarios":"Calling FullSink.Write or FullSink.Close before Open, after a failed Open (e.g. Open returned ErrHeaderInvalid), or after Close already ran.","commonSituations":"Calling Write on a zero-value/reused sink; ignoring an error from Open and proceeding to Write; double-Close in cleanup paths.","solutions":["Check the error returned by Open before writing; only Write/Close after a successful Open.","Ensure Close is called at most once, e.g. via sync.Once or a flag.","If Open failed, discard the sink and create a fresh one."],"exampleFix":"// before\nsink.Write(data) // ErrSinkNotOpen\n// after\nif err := sink.Open(); err != nil { return err }\nif _, err := sink.Write(data); err != nil { return err }","handlingStrategy":"validation","validationCode":"// Verify Open succeeded before writing\nif err := sink.Open(); err != nil {\n    return fmt.Errorf(\"cannot write sink: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if _, err := sink.Write(p); err != nil {\n    if errors.Is(err, snapshot.ErrSinkNotOpen) {\n        return fmt.Errorf(\"sink lifecycle bug: write before open: %w\", err)\n    }\n    return err\n}","preventionTips":["Always check Open's error before Write/Close.","Use defer sink.Close() only after a successful Open.","Discard sinks whose Open failed; never proceed with them."],"tags":["snapshot","lifecycle","rqlite"],"backgroundTag":"resource-not-open","analyzedSha":"7586a4d1bdbd9a5a80021664c5a863cd850adb60","analyzedAt":"2026-09-03T07:03:02.260Z","contentChangedAt":"2026-09-03T07:03:02.260Z","schemaVersion":2},"datasetVersion":"2026-09-10T12:17:11.382Z"}