benbjohnson/litestream · error

failed to configure replica %d for %s: %w

Error message

failed to configure replica %d for %s: %w

What it means

This error wraps a failure that occurred while deep-copying and rewriting one entry of the deprecated 'replicas' array in a database config directory entry. Litestream resolves replica URLs against the database's relative path; if a replica config cannot be cloned (typically because its path is a URL or malformed), startup of that database is aborted and the underlying cause is chained via %w.

Source

Thrown at cmd/litestream/main.go:920

	}

	// Deep copy replica config and make path unique per database.
	// This prevents all databases from writing to the same replica path.
	if dbc.Replica != nil {
		replicaCopy, err := cloneReplicaConfigWithRelativePath(dbc.Replica, relPath)
		if err != nil {
			return nil, fmt.Errorf("failed to configure replica for %s: %w", dbPath, err)
		}
		dbConfigCopy.Replica = replicaCopy
	}

	// Also handle deprecated 'replicas' array field.
	if len(dbc.Replicas) > 0 {
		dbConfigCopy.Replicas = make([]*ReplicaConfig, len(dbc.Replicas))
		for i, replica := range dbc.Replicas {
			replicaCopy, err := cloneReplicaConfigWithRelativePath(replica, relPath)
			if err != nil {
				return nil, fmt.Errorf("failed to configure replica %d for %s: %w", i, dbPath, err)
			}
			dbConfigCopy.Replicas[i] = replicaCopy
		}
	}

	return NewDBFromConfig(&dbConfigCopy)
}

// cloneReplicaConfigWithRelativePath returns a copy of the replica configuration with the
// database-relative path appended to either the replica path or URL, depending on how the
// replica was configured.
func cloneReplicaConfigWithRelativePath(base *ReplicaConfig, relPath string) (*ReplicaConfig, error) {
	if base == nil {
		return nil, nil
	}

	replicaCopy := *base
	relPath = filepath.ToSlash(relPath)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Move the replica out of the deprecated `replicas` array into a top-level replica config with an explicit `url` field
  2. Fix the offending replica path so it is a relative path, not a URL (read the wrapped %w cause for the exact parse failure)
  3. Use `litestream replicate -config <file>` with a single validated config file to isolate which replica entry fails

Example fix

# before (deprecated)
dbs:
  - path: /data/db.sqlite
    replicas:
      - path: file:///backups/db
# after
dbs:
  - path: /data/db.sqlite
    replicas:
      - url: file:///backups/db
Defensive patterns

Strategy: validation

Validate before calling

for i, r := range dbc.Replicas {
    if r.Path != "" && strings.Contains(r.Path, "://") {
        return fmt.Errorf("replicas[%d]: path %q looks like a URL; use 'url' field", i, r.Path)
    }
    if r.URL != "" {
        if _, err := url.Parse(r.URL); err != nil {
            return fmt.Errorf("replicas[%d]: invalid url: %w", i, err)
        }
    }
}

Prevention

When it happens

Trigger: Running `litestream replicate -config <dir>` where a YAML/JSON file in the config directory uses the deprecated `replicas:` array and one replica entry fails cloneReplicaConfigWithRelativePath — most often a replica whose `path` field contains a full URL that cannot be parsed or is rejected.

Common situations: Migrating old v0.3.x configs that used a replicas array with inline path-style S3 locations; a typo'd replica path value that url.Parse or path handling rejects.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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