benbjohnson/litestream · error

unsupported replica URL scheme: %q

Error message

unsupported replica URL scheme: %q

What it means

NewReplicaClientFromURL looks up a registered ReplicaClientFactory by URL scheme; if no backend package registered a factory for that scheme (s3, gs, abs, file, sftp, webdav, ...), this error is returned. Usually it means the storage backend package was not imported, so its init() never registered the factory.

Source

Thrown at replica_url.go:49

// The URL scheme determines which backend is used (s3, gs, abs, file, etc.).
func NewReplicaClientFromURL(rawURL string) (ReplicaClient, error) {
	scheme, host, urlPath, query, userinfo, err := ParseReplicaURLWithQuery(rawURL)
	if err != nil {
		return nil, err
	}

	// Normalize webdavs to webdav
	factoryScheme := scheme
	if factoryScheme == "webdavs" {
		factoryScheme = "webdav"
	}

	replicaClientFactoriesMu.RLock()
	factory, ok := replicaClientFactories[factoryScheme]
	replicaClientFactoriesMu.RUnlock()

	if !ok {
		return nil, fmt.Errorf("unsupported replica URL scheme: %q", scheme)
	}

	return factory(scheme, host, urlPath, query, userinfo)
}

// ReplicaTypeFromURL returns the replica type from a URL string.
// Returns empty string if the URL is invalid or has no scheme.
func ReplicaTypeFromURL(rawURL string) string {
	if !IsURL(rawURL) {
		return ""
	}
	scheme, _, _, _ := ParseReplicaURL(rawURL)
	if scheme == "" {
		return ""
	}
	if scheme == "webdavs" {
		return "webdav"
	}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Add a blank import of the backend package so its init() registers the factory (e.g. `_ "github.com/benbjohnson/litestream/s3"`).
  2. Fix the URL scheme spelling to a supported one (s3, gs, abs, file, sftp, webdav/webdavs).
  3. If using the litestream binary, ensure it's built with the desired backends (all official builds include them).
  4. Verify with ReplicaTypeFromURL or the registry that the scheme is registered before calling.

Example fix

// before: main.go missing backend
import "github.com/benbjohnson/litestream"
client, err := litestream.NewReplicaClientFromURL("s3://bucket/db") // unsupported scheme
// after: blank-import the backend
import (
    "github.com/benbjohnson/litestream"
    _ "github.com/benbjohnson/litestream/s3"
)
Defensive patterns

Strategy: validation

Validate before calling

u, _ := url.Parse(replicaURL)
supported := map[string]bool{"s3": true, "gs": true, "abs": true, "file": true, "sftp": true, "webdav": true, "webdavs": true}
if !supported[strings.ToLower(u.Scheme)] { return fmt.Errorf("scheme %q not compiled in; add backend import", u.Scheme) }

Type guard

func schemeRegistered(rawURL string) bool {
    u, err := url.Parse(rawURL)
    if err != nil { return false }
    s := strings.ToLower(u.Scheme)
    if s == "webdavs" { s = "webdav" }
    return litestream.ReplicaTypeFromURL(rawURL) == s && s != ""
}

Try / catch

client, err := litestream.NewReplicaClientFromURL(rawURL)
if err != nil {
    var se *url.Error
    if strings.Contains(err.Error(), "unsupported replica URL scheme") { return fmt.Errorf("backend for %q not linked into binary; add blank import of its package", parseScheme(rawURL)) }
    return err
}

Prevention

When it happens

Trigger: Calling NewReplicaClientFromURL with a replica URL whose scheme has no registered factory — typically because the backend package (e.g. litestream.io/s3) isn't imported (blank import) in the binary, or the scheme string is misspelled.

Common situations: Building a custom binary that forgot `_ "github.com/benbjohnson/litestream/s3"`; using `s3a://`, `s3://` vs vendor-specific schemes, or typo'd schemes like `gcs://` instead of `gs://`; version upgrades where a backend moved packages.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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