{"record":{"id":"b117c0b4ff45a8c7","repo":"benbjohnson/litestream","slug":"no-backup-files-available-w","errorCode":null,"errorMessage":"no backup files available: %w","messagePattern":"no backup files available: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"vfs.go","lineNumber":2851,"sourceCode":"\t\t}\n\t\treturn infos, nil\n\t}\n\n\t// For read-only mode, wait for files to become available\n\tfor {\n\t\tinfos, err := CalcRestorePlan(f.ctx, f.client, 0, time.Time{}, f.logger)\n\t\tif err == nil {\n\t\t\treturn infos, nil\n\t\t}\n\t\tif !errors.Is(err, ErrTxNotAvailable) {\n\t\t\treturn nil, fmt.Errorf(\"cannot calc restore plan: %w\", err)\n\t\t}\n\n\t\tf.logger.Debug(\"no backup files available yet, waiting\", \"interval\", f.PollInterval)\n\t\tselect {\n\t\tcase <-time.After(f.PollInterval):\n\t\tcase <-f.ctx.Done():\n\t\t\treturn nil, fmt.Errorf(\"no backup files available: %w\", f.ctx.Err())\n\t\t}\n\t}\n}\n\n// RegisterVFSConnection maps a SQLite connection handle to its VFS file ID.\nfunc RegisterVFSConnection(dbPtr uintptr, fileID uint64) error {\n\tif _, ok := lookupVFSFile(fileID); !ok {\n\t\treturn fmt.Errorf(\"vfs file not found: id=%d\", fileID)\n\t}\n\tvfsConnectionMap.Store(dbPtr, fileID)\n\treturn nil\n}\n\n// UnregisterVFSConnection removes a connection mapping.\nfunc UnregisterVFSConnection(dbPtr uintptr) {\n\tvfsConnectionMap.Delete(dbPtr)\n}\n","sourceCodeStart":2833,"sourceCodeEnd":2869,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L2833-L2869","documentation":"When CalcRestorePlan returns ErrTxNotAvailable, the VFS polls at PollInterval waiting for backup files to appear. If the context is canceled before any files arrive, this error wraps ctx.Err(). It is the clean shutdown/timeout path for \"no backup data yet\".","triggerScenarios":"Opening a VFS file against an empty or not-yet-synced replica and canceling the context (Ctrl-C, HTTP timeout, deadline exceeded) before the first LTX file shows up.","commonSituations":"Restore script with a short timeout hitting a replica that only syncs every N seconds; user interrupt during a long wait; Kubernetes probe timeouts canceling an initial VFS open against a cold replica.","solutions":["Increase the context deadline so it exceeds the replication interval plus PollInterval","Trigger a replication sync first so LTX files exist before VFS open","Verify the replica path is correct — an empty listing means you are polling forever","If waiting is not desired, fail fast by checking replica contents before opening"],"exampleFix":"// before: deadline shorter than replication interval\nctx, cancel := context.WithTimeout(ctx, 2*time.Second)\n// after: allow enough time for the next poll to see new files\nctx, cancel := context.WithTimeout(ctx, 2*f.PollInterval+30*time.Second)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nif err := openVFS(ctx); err != nil {\n    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n        return retryWithBackoff(ctx, openVFS)\n    }\n    return err\n}","preventionTips":["Set deadlines longer than replication interval + PollInterval","Seed the replica before VFS open","Fix wiring if poll never finds data (empty listing means wrong path)"],"tags":["vfs","timeout","context","restore"],"backgroundTag":"request-timeout","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}