benbjohnson/litestream · warning

no backup files available: %w

Error message

no backup files available: %w

What it means

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".

Source

Thrown at vfs.go:2851

		}
		return infos, nil
	}

	// For read-only mode, wait for files to become available
	for {
		infos, err := CalcRestorePlan(f.ctx, f.client, 0, time.Time{}, f.logger)
		if err == nil {
			return infos, nil
		}
		if !errors.Is(err, ErrTxNotAvailable) {
			return nil, fmt.Errorf("cannot calc restore plan: %w", err)
		}

		f.logger.Debug("no backup files available yet, waiting", "interval", f.PollInterval)
		select {
		case <-time.After(f.PollInterval):
		case <-f.ctx.Done():
			return nil, fmt.Errorf("no backup files available: %w", f.ctx.Err())
		}
	}
}

// RegisterVFSConnection maps a SQLite connection handle to its VFS file ID.
func RegisterVFSConnection(dbPtr uintptr, fileID uint64) error {
	if _, ok := lookupVFSFile(fileID); !ok {
		return fmt.Errorf("vfs file not found: id=%d", fileID)
	}
	vfsConnectionMap.Store(dbPtr, fileID)
	return nil
}

// UnregisterVFSConnection removes a connection mapping.
func UnregisterVFSConnection(dbPtr uintptr) {
	vfsConnectionMap.Delete(dbPtr)
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Increase the context deadline so it exceeds the replication interval plus PollInterval
  2. Trigger a replication sync first so LTX files exist before VFS open
  3. Verify the replica path is correct — an empty listing means you are polling forever
  4. If waiting is not desired, fail fast by checking replica contents before opening

Example fix

// before: deadline shorter than replication interval
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
// after: allow enough time for the next poll to see new files
ctx, cancel := context.WithTimeout(ctx, 2*f.PollInterval+30*time.Second)
Defensive patterns

Strategy: retry

Try / catch

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
if err := openVFS(ctx); err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        return retryWithBackoff(ctx, openVFS)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/b117c0b4ff45a8c7. Report an issue: GitHub.