{"record":{"id":"221defeac461b680","repo":"benbjohnson/litestream","slug":"webdav-url-required","errorCode":null,"errorMessage":"webdav url required","messagePattern":"webdav url required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"webdav/replica_client.go","lineNumber":106,"sourceCode":"\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.\nfunc (c *ReplicaClient) init(ctx context.Context) (_ *gowebdav.Client, err error) {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tif c.client != nil {\n\t\treturn c.client, nil\n\t}\n\n\tif c.URL == \"\" {\n\t\treturn nil, fmt.Errorf(\"webdav url required\")\n\t}\n\n\tc.client = gowebdav.NewClient(c.URL, c.Username, c.Password)\n\n\tc.client.SetTimeout(c.Timeout)\n\n\tif err := c.client.Connect(); err != nil {\n\t\tc.client = nil\n\t\treturn nil, fmt.Errorf(\"webdav: cannot connect to server: %w\", err)\n\t}\n\n\treturn c.client, nil\n}\n\nfunc (c *ReplicaClient) DeleteAll(ctx context.Context) error {\n\tclient, err := c.init(ctx)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/webdav/replica_client.go#L88-L124","documentation":"ReplicaClient.init lazily creates the underlying gowebdav client and requires the URL field to be set. This error is thrown when init is called on a ReplicaClient whose URL is empty — i.e. the client was constructed without a server URL (or via a code path that never parsed/populated it).","triggerScenarios":"Using the webdav ReplicaClient programmatically (webdav.NewReplicaClient()) without setting the URL field before any operation (Init, LTXFiles, Write, DeleteAll); deserializing config that omitted the URL.","commonSituations":"Building the client in code and forgetting to populate fields that the URL parser normally fills; loading a replica config section with a missing 'url' key; constructing the struct manually instead of via NewReplicaClientFromURL.","solutions":["Set c.URL (and credentials/path) before calling Init or any replica operation, or build the client with NewReplicaClientFromURL(\"webdav://host/path\")","Fix the config so the webdav replica block includes a 'url' key with scheme, host and path","Ensure the config section is actually being parsed into the ReplicaClient (check key names/casing)","Validate config at startup so an empty URL fails fast with a clear message"],"exampleFix":"// before\nc := webdav.NewReplicaClient()\nc.Path = \"/dav/litestream\"\n// after\nc, err := webdav.NewReplicaClientFromURL(\"webdav://user:pass@dav.example.com/dav/litestream\")","handlingStrategy":"validation","validationCode":"if client.URL == \"\" {\n    return errors.New(\"webdav replica client requires a URL before Init\")\n}","typeGuard":"func (c *webdav.ReplicaClient) Configured() bool { return c.URL != \"\" }","tryCatchPattern":"if _, err := rc.Init(ctx); err != nil && strings.Contains(err.Error(), \"webdav url required\") {\n    return fmt.Errorf(\"replica client built without URL — use NewReplicaClientFromURL: %w\", err)\n}","preventionTips":["Always construct the client via webdav.NewReplicaClientFromURL rather than the bare struct","Validate the full replica config (url, path, credentials) before starting replication","Add a startup smoke test that calls Init on every replica","Check config key names so the 'url' field actually parses into the client"],"tags":["webdav","config","initialization","url"],"backgroundTag":"empty-required-field","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}