benbjohnson/litestream · error

cannot specify url & host for sftp replica

Error message

cannot specify url & host for sftp replica

What it means

newSFTPReplicaClientFromConfig rejects configs that set both 'url' and the individual 'host' field for an sftp replica. Host is a constituent of the URL, so specifying both is ambiguous and the constructor fails fast at startup.

Solutions

  1. Remove the 'host' field and let the URL provide the host
  2. Or drop 'url' and keep host/user/password/path fields individually
  3. If host must differ from the URL's, use separate fields only (no url)

Example fix

# before
- type: sftp
  url: sftp://user@host/db
  host: other.example.com
# after
- type: sftp
  url: sftp://user@host/db
Defensive patterns

Strategy: validation

Validate before calling

if rep.Type == "sftp" && rep.URL != "" && rep.Host != "" {
    return fmt.Errorf("sftp replica %s: url and host are mutually exclusive", rep.Name)
}

Prevention

When it happens

Trigger: An sftp replica config where c.URL is non-empty AND c.Host is non-empty, e.g. url: 'sftp://backup.example.com/db' plus host: 'backup.example.com'.

Common situations: Copy-pasting a URL into an existing config that already had host: set; automation that fills all fields from a template regardless of which style is used.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at cmd/litestream/main.go:1807

			client.Path = strings.TrimPrefix(path.Clean(u.Path), "/")
		}
	}

	// Ensure required settings are set.
	if client.Bucket == "" {
		return nil, fmt.Errorf("bucket required for abs replica")
	}

	return client, nil
}

// newSFTPReplicaClientFromConfig returns a new instance of sftp.ReplicaClient built from config.
func newSFTPReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_ *sftp.ReplicaClient, err error) {
	// Ensure URL & constituent parts are not both specified.
	if c.URL != "" && c.Path != "" {
		return nil, fmt.Errorf("cannot specify url & path for sftp replica")
	} else if c.URL != "" && c.Host != "" {
		return nil, fmt.Errorf("cannot specify url & host for sftp replica")
	}

	host, user, password, path := c.Host, c.User, c.Password, c.Path

	// Apply settings from URL, if specified.
	if c.URL != "" {
		u, err := url.Parse(c.URL)
		if err != nil {
			return nil, err
		}

		// Only apply URL parts to field that have not been overridden.
		if host == "" {
			host = u.Host
		}
		if user == "" && u.User != nil {
			user = u.User.Username()
		}

View on GitHub (pinned to 4ed7a308f6)