benbjohnson/litestream · error

invalid NATS URL: %w

Error message

invalid NATS URL: %w

What it means

newNATSReplicaClientFromConfig parses c.URL via litestream.ParseReplicaURL to extract the server host and bucket; if that parser returns an error (unparseable or wrong-shape URL), the failure is wrapped as 'invalid NATS URL: %w' so the underlying parse error is preserved.

Source

Thrown at cmd/litestream/main.go:1919

	// Build replica.
	client := webdav.NewReplicaClient()
	client.URL = webdavURL
	client.Username = username
	client.Password = password
	client.Path = path

	return client, nil
}

// newNATSReplicaClientFromConfig returns a new instance of nats.ReplicaClient built from config.
func newNATSReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_ *nats.ReplicaClient, err error) {
	// Parse URL if provided to extract bucket name and server URL
	var url, bucket string
	if c.URL != "" {
		scheme, host, bucketPath, err := litestream.ParseReplicaURL(c.URL)
		if err != nil {
			return nil, fmt.Errorf("invalid NATS URL: %w", err)
		}
		if scheme != "nats" {
			return nil, fmt.Errorf("invalid scheme for NATS replica: %s", scheme)
		}

		// Reconstruct URL without bucket path
		if host != "" {
			url = fmt.Sprintf("nats://%s", host)
		}

		// Extract bucket name from path
		if bucketPath != "" {
			bucket = strings.Trim(bucketPath, "/")
		}
	}

	// Use bucket from config if not extracted from URL
	if bucket == "" {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Set a well-formed NATS URL like 'nats://nats.example.com:4222/mybucket' (host and bucket path)
  2. Inspect the wrapped cause after 'invalid NATS URL:' in the log to see the exact parse failure
  3. URL-encode special characters or remove them from the config value

Example fix

# before
- type: nats
  url: nats://nats.example.com :4222/bucket
# after
- type: nats
  url: nats://nats.example.com:4222/bucket
Defensive patterns

Strategy: validation

Validate before calling

if rep.Type == "nats" && rep.URL != "" {
    if _, _, _, err := litestream.ParseReplicaURL(rep.URL); err != nil {
        return fmt.Errorf("nats replica %s: bad url: %w", rep.Name, err)
    }
}

Type guard

func validNATSURL(raw string) bool {
    scheme, _, _, err := litestream.ParseReplicaURL(raw)
    return err == nil && scheme == "nats"
}

Try / catch

if _, err := newNATSReplicaClientFromConfig(cfg, rep); err != nil {
    var cause error
    if strings.HasPrefix(err.Error(), "invalid NATS URL:") {
        // log full wrapped chain with %v / errors.Unwrap
    }
    _ = cause
}

Prevention

When it happens

Trigger: A nats replica whose 'url' cannot be parsed by ParseReplicaURL — e.g. missing scheme ('nats://'), control characters, or a URL that fails net/url parsing rules.

Common situations: Hand-edited config URLs with unescaped characters or spaces; leaving 'url:' with an empty-but-present value in some parsing paths; copy errors inserting a quote into the URL.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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