{"record":{"id":"5efb233e7c3218c5","repo":"benbjohnson/litestream","slug":"webdav-cannot-delete-ltx-file-q-w","errorCode":null,"errorMessage":"webdav: cannot delete ltx file %q: %w","messagePattern":"webdav: cannot delete ltx file %q: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"webdav/replica_client.go","lineNumber":365,"sourceCode":"\t\t}\n\t\treturn nil, fmt.Errorf(\"webdav: cannot read file %q: %w\", filename, err)\n\t}\n\treturn rc, nil\n}\n\nfunc (c *ReplicaClient) DeleteLTXFiles(ctx context.Context, a []*ltx.FileInfo) error {\n\tclient, err := c.init(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, info := range a {\n\t\tfilename := litestream.LTXFilePath(c.Path, info.Level, info.MinTXID, info.MaxTXID)\n\n\t\tc.logger.Debug(\"deleting ltx file\", \"level\", info.Level, \"minTXID\", info.MinTXID, \"maxTXID\", info.MaxTXID, \"path\", filename)\n\n\t\tif err := client.Remove(filename); err != nil && !os.IsNotExist(err) && !gowebdav.IsErrNotFound(err) {\n\t\t\treturn fmt.Errorf(\"webdav: cannot delete ltx file %q: %w\", filename, err)\n\t\t}\n\t\tinternal.OperationTotalCounterVec.WithLabelValues(ReplicaClientType, \"DELETE\").Inc()\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":347,"sourceCodeEnd":372,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/webdav/replica_client.go#L347-L372","documentation":"This error wraps an underlying failure returned by the WebDAV server's Remove() call when Litestream tries to delete an LTX (replication) file. It is only raised when the error is neither os.IsNotExist nor a gowebdav IsErrNotFound, i.e. a real failure rather than the file already being gone. Litestream surfaces the offending filename and the wrapped cause so the replication cleanup can be diagnosed.","triggerScenarios":"Calling ReplicaClient.DeleteLTXFiles on a WebDAV replica when the server returns 403 Forbidden (read-only share/credentials), 401 Unauthorized (bad password), 500 (server-side error), a connection failure/time-out mid-delete, or a path escaping issues (bad c.Path base URL).","commonSituations":"WebDAV account lacks write permission on the replica directory; server returned 401 due to rotated credentials not updated in config; reverse proxy or gateway returned 5xx; transient network drop during retention cleanup; misconfigured path in litestream.yml.","solutions":["Check WebDAV credentials and that the account has DELETE permission on the replica path","Read the wrapped cause (%w) in logs to identify the HTTP status from gowebdav and fix the server-side condition","Verify the litestream.yml webdav url/path is correct and reachable (test with curl -X DELETE)","Retry after transient network/server errors; Litestream will retry the sync loop and re-attempt deletion","If files were already removed out-of-band, no action needed: not-found errors are tolerated"],"exampleFix":"// before: read-only WebDAV credentials cause 403\ncollector: litestream.yml webdav:\n  url: https://dav.example.com/litestream\n  username: reader\n  password: ****\n// after: use credentials with write access\n  url: https://dav.example.com/litestream\n  username: writer\n  password: ****","handlingStrategy":"try-catch","validationCode":"// Go: check WebDAV reachability and permissions before deleting\nclient := gowebdav.NewClient(url)\nclient.SetBasicAuth(user, pass)\nif err := client.Connect(); err != nil {\n    return fmt.Errorf(\"webdav unreachable: %w\", err)\n}\nif _, err := client.ReadDir(basePath); err != nil {\n    return fmt.Errorf(\"no read/write access to %s: %w\", basePath, err)\n}","typeGuard":"func isNotFoundErr(err error) bool {\n    return os.IsNotExist(err) || gowebdav.IsErrNotFound(err)\n}\n// treat only non-not-found errors as fatal, like litestream does","tryCatchPattern":"if err := replicaClient.DeleteLTXFiles(ctx, infos); err != nil {\n    var davErr *gowebdav.StatusError\n    if errors.As(err, &davErr) {\n        log.Printf(\"webdav delete failed status=%d: %v\", davErr.Status, davErr)\n    } else {\n        log.Printf(\"webdav delete failed: %v\", err)\n    }\n    // transient: let the next sync retry\n    return err\n}","preventionTips":["Grant the WebDAV service account DELETE permission on the replica directory","Test the URL/credentials with curl -u user:pass -X DELETE before configuring","Rotate credentials in litestream.yml in sync with the server","Monitor logs for the wrapped cause (%w) to distinguish 401/403/5xx/network"],"tags":["webdav","storage","deletion","network"],"backgroundTag":"file-delete-failed","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"}