{"record":{"id":"3bd8123df446c8e8","repo":"gofr-dev/gofr","slug":"w-for-q-w","errorCode":null,"errorMessage":"%w for %q: %w","messagePattern":"%w for %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gofr/datasource/file/ftp/storage_adapter.go","lineNumber":108,"sourceCode":"// NewReader creates a reader for the given object.\nfunc (s *storageAdapter) NewReader(_ context.Context, name string) (io.ReadCloser, error) {\n\tif name == \"\" {\n\t\treturn nil, errEmptyObjectName\n\t}\n\n\tif s.conn == nil {\n\t\treturn nil, errFTPClientNotInitialized\n\t}\n\n\tobjectPath := s.buildPath(name)\n\n\treader, err := s.conn.Retr(objectPath)\n\tif err != nil {\n\t\tif isFTPNotFoundError(err) {\n\t\t\treturn nil, fmt.Errorf(\"%w %q: %w\", errObjectNotFound, name, err)\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"%w for %q: %w\", errFailedToCreateReader, name, err)\n\t}\n\n\treturn reader, nil\n}\n\n// NewRangeReader creates a range reader for the given object.\nfunc (s *storageAdapter) NewRangeReader(_ context.Context, name string, offset, length int64) (io.ReadCloser, error) {\n\tif name == \"\" {\n\t\treturn nil, errEmptyObjectName\n\t}\n\n\tif offset < 0 {\n\t\treturn nil, fmt.Errorf(\"%w (got: %d)\", errInvalidOffset, offset)\n\t}\n\n\tif s.conn == nil {\n\t\treturn nil, errFTPClientNotInitialized\n\t}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/datasource/file/ftp/storage_adapter.go#L90-L126","documentation":"NewReader failed to open the file for a reason other than not-found: RETR returned an error that isFTPNotFoundError did not classify as missing-object, so the library wraps it with errFailedToCreateReader. This represents transient or server-side failures (connection drops, permission denied, server busy).","triggerScenarios":"storageAdapter.NewReader called when s.conn.Retr(objectPath) fails with any error that is not classified as FTP not-found (e.g. 4xx/5xx responses, closed connection, permission denied).","commonSituations":"FTP connection dropped/idle-timed out before the call, insufficient permissions on the file, server out of sessions, network interruption mid-command, TLS renegotiation failure.","solutions":["Inspect the wrapped cause with errors.Unwrap to see the raw FTP response code","Reconnect/re-establish the FTP connection if it was closed or timed out (retry the operation)","Check file permissions on the FTP server for the authenticated user","If the file truly does not exist but returns a non-standard message, verify isFTPNotFoundError covers your server's response format"],"exampleFix":"// before\nr, err := store.NewReader(ctx, \"data/report.csv\") // fails after idle timeout\n// after\nif err := ftpConn.Close(); err != nil { }\nftpConn, _ = ftp.DialAndLogin(...) // re-dial before retrying\nr, err := store.NewReader(ctx, \"data/report.csv\")","handlingStrategy":"retry","validationCode":"if store == nil || ftpConn == nil {\n    return errors.New(\"ftp client not initialized\")\n}","typeGuard":"func isFTPNotFound(err error) bool { return errors.Is(err, errObjectNotFound) }","tryCatchPattern":"r, err := store.NewReader(ctx, name)\nif err != nil && !errors.Is(err, errObjectNotFound) {\n    // transient: reconnect FTP and retry with backoff\n    r, err = retryWithBackoff(3, func() (io.ReadCloser, error) { return store.NewReader(ctx, name) })\n}","preventionTips":["Keep FTP connections alive or re-dial after idle timeouts","Check file permissions for the FTP user","Log the unwrapped cause to see the raw FTP response code"],"tags":["ftp","network","reader"],"backgroundTag":"ftp-retr-failed","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}