{"record":{"id":"697948c69d6d94f4","repo":"benbjohnson/litestream","slug":"host-required-for-webdav-replica-url","errorCode":null,"errorMessage":"host required for webdav replica URL","messagePattern":"host required for webdav replica URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"webdav/replica_client.go","lineNumber":78,"sourceCode":"// This is used by the replica client factory registration.\n// URL format: webdav://[user[:password]@]host[:port]/path or webdavs://... (for HTTPS)\nfunc NewReplicaClientFromURL(scheme, host, urlPath string, query url.Values, userinfo *url.Userinfo) (litestream.ReplicaClient, error) {\n\tclient := NewReplicaClient()\n\n\t// Determine HTTP or HTTPS based on scheme\n\thttpScheme := \"http\"\n\tif scheme == \"webdavs\" {\n\t\thttpScheme = \"https\"\n\t}\n\n\t// Extract credentials from userinfo\n\tif userinfo != nil {\n\t\tclient.Username = userinfo.Username()\n\t\tclient.Password, _ = userinfo.Password()\n\t}\n\n\tif host == \"\" {\n\t\treturn nil, fmt.Errorf(\"host required for webdav replica URL\")\n\t}\n\n\tclient.URL = fmt.Sprintf(\"%s://%s\", httpScheme, host)\n\tclient.Path = urlPath\n\n\treturn client, nil\n}\n\nfunc (c *ReplicaClient) Type() string {\n\treturn ReplicaClientType\n}\n\nfunc (c *ReplicaClient) Init(ctx context.Context) error {\n\t_, err := c.init(ctx)\n\treturn err\n}\n\n// init initializes the connection and returns the WebDAV client.","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/webdav/replica_client.go#L60-L96","documentation":"When parsing a webdav:// replica URL, NewReplicaClientFromURL requires a host component to build the client's base URL. This error is thrown when the URL parses but contains no host (e.g. 'webdav:///path' or 'webdav://').","triggerScenarios":"Configuring a replica URL like 'webdav:///dav' or 'webdav://:8080/path' (empty host), or programmatically passing a URL built without the host part.","commonSituations":"YAML config typo where the hostname was omitted or the URL was split across lines; templating/config expansion left the host variable empty (unset env var interpolated to nothing).","solutions":["Add the host to the replica URL: webdav://user:pass@myserver.example.com:port/path","Check the config with 'litestream replicas' or re-read the YAML — ensure nothing stripped the host (e.g. $HOST env var empty)","Validate the URL with a parser before applying config: u, err := url.Parse(s); u.Host != \"\"","If credentials live in the URL, confirm the '@' separates userinfo from the host and no '/' got misplaced"],"exampleFix":"// before\nurl: \"webdav:///dav/litestream\"\n// after\nurl: \"webdav://user:pass@dav.example.com:5005/dav/litestream\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(cfg.WebdavURL)\nif err != nil { return err }\nif u.Host == \"\" {\n    return fmt.Errorf(\"webdav replica URL %q has no host\", cfg.WebdavURL)\n}","typeGuard":"func hasURLHost(raw string) bool {\n    u, err := url.Parse(raw)\n    return err == nil && u.Host != \"\"\n}","tryCatchPattern":"client, err := webdav.NewReplicaClientFromURL(raw)\nif err != nil && strings.Contains(err.Error(), \"host required\") {\n    return fmt.Errorf(\"check webdav url in config, host part missing: %w\", err)\n}","preventionTips":["Validate replica URLs with url.Parse at config-load time","Keep scheme, host and path on one line in YAML to avoid splitting","Watch for empty env-var interpolation in templated URLs","Include port explicitly when non-default"],"tags":["webdav","url","config","validation"],"backgroundTag":"invalid-url","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}