{"record":{"id":"9ff1f255eea099b1","repo":"benbjohnson/litestream","slug":"init-per-connection-replica-client-w","errorCode":null,"errorMessage":"init per-connection replica client: %w","messagePattern":"init per-connection replica client: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"vfs.go","lineNumber":165,"sourceCode":"}\n\nfunc (vfs *VFS) openMainDB(name string, uriParameters map[string]string, flags sqlite3vfs.OpenFlag) (sqlite3vfs.File, sqlite3vfs.OpenFlag, error) {\n\tcfg, err := vfs.configForOpen(name, uriParameters)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\tclient := vfs.client\n\tvar perConnClient bool\n\tif cfg != nil && cfg.ReplicaURL != \"\" {\n\t\tclient, err = NewReplicaClientFromURL(cfg.ReplicaURL)\n\t\tif err != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"create per-connection replica client: %w\", err)\n\t\t}\n\t\tif err := client.Init(context.Background()); err != nil {\n\t\t\tif closer, ok := client.(io.Closer); ok {\n\t\t\t\tif closeErr := closer.Close(); closeErr != nil {\n\t\t\t\t\treturn nil, 0, fmt.Errorf(\"init per-connection replica client: %w\", errors.Join(err, closeErr))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil, 0, fmt.Errorf(\"init per-connection replica client: %w\", err)\n\t\t}\n\t\tperConnClient = true\n\t}\n\n\tif client == nil {\n\t\treturn nil, 0, fmt.Errorf(\"no replica client configured: set LITESTREAM_REPLICA_URL, use SetVFSConfig, or pass replica_url in the database URI\")\n\t}\n\n\tf := NewVFSFile(client, name, vfs.logger.With(\"name\", name))\n\tf.PollInterval = vfs.PollInterval\n\tf.CacheSize = vfs.CacheSize\n\tf.vfs = vfs\n\tf.perConnClient = perConnClient\n\n\tif cfg != nil {","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L147-L183","documentation":"In openMainDB, after creating a per-connection replica client from cfg.ReplicaURL, the client must be initialized with client.Init(context.Background()). This error is returned when Init fails AND the subsequent client.Close() also fails; both errors are joined with errors.Join. Litestream throws it because an uninitialized replica client cannot serve reads and the failed client also could not be cleaned up, signalling two simultaneous problems.","triggerScenarios":"Opening a VFS database whose per-connection replica_url points to a backend that fails Init (bad credentials, unreachable endpoint, missing bucket) and where the client implements io.Closer but Close() returns an error (e.g. session cleanup failure on sftp, HTTP client close error).","commonSituations":"Expired or wrong cloud credentials combined with flaky network; SFTP backend whose SSH session teardown fails; a custom ReplicaClient with buggy Close implementation.","solutions":["Read the joined error: fix the underlying Init failure first (credentials, endpoint, bucket existence, network reachability).","Validate the replica_url independently before opening (e.g. construct and Init the client in a probe, or run 'litestream ltx -replica <url>').","Check environment variables/credentials for the backend (AWS_*, GOOGLE_APPLICATION_CREDENTIALS, AZURE_STORAGE_*) are present and valid.","If Close errors persist, upgrade the storage backend package — a failing Close on an already-failed client usually indicates a driver bug."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"client, err := litestream.NewReplicaClientFromURL(replicaURL)\nif err == nil {\n    if err := client.Init(ctx); err != nil { return fmt.Errorf(\"replica unreachable: %w\", err) }\n}","typeGuard":null,"tryCatchPattern":"db, err := sql.Open(\"sqlite\", dsn)\nif err != nil {\n    var joined interface{ Unwrap() []error }\n    if errors.As(err, &multiErr) { /* inspect each joined error */ }\n    return retryWithBackoff(func() error { return reopenDB(dsn) })\n}","preventionTips":["Probe Init on the replica URL during application startup, before serving traffic","Validate cloud credentials exist (AWS_*, GOOGLE_APPLICATION_CREDENTIALS, AZURE_STORAGE_*) at boot","Use short health-check calls against the storage backend to catch auth/network issues early","Keep backend driver packages updated so Close failure paths are fixed"],"tags":["replica-client","initialization-failure","cloud-storage","resource-cleanup"],"backgroundTag":"api-request-failed","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"}