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
- Set a well-formed NATS URL like 'nats://nats.example.com:4222/mybucket' (host and bucket path)
- Inspect the wrapped cause after 'invalid NATS URL:' in the log to see the exact parse failure
- 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
- Validate nats URLs with ParseReplicaURL before writing config
- Avoid unescaped spaces/special chars in config URLs
- Test the exact config file with litestream before restarts
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
- invalid scheme for NATS replica: %s
- failed to configure replica for %s: %w
- bucket required for nats replica URL
- heartbeat URL must be a valid HTTP or HTTPS URL
- database config #%d: 'watch' can only be enabled with a dire
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/0bf8073b00cffb41.
Report an issue: GitHub.