{"record":{"id":"5731ba300987a75d","repo":"gofr-dev/gofr","slug":"w-q-w","errorCode":null,"errorMessage":"%w %q: %w","messagePattern":"%w %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gofr/datasource/file/ftp/storage_adapter.go","lineNumber":105,"sourceCode":"\treturn nil\n}\n\n// 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","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/datasource/file/ftp/storage_adapter.go#L87-L123","documentation":"NewReader failed to RETRieve the file from the FTP server, but the underlying error was classified as 'object not found' (errObjectNotFound) via isFTPNotFoundError. The library wraps the sentinel with the requested name and the raw FTP error so callers can errors.Is-test for a missing object. It means the path resolved by buildPath does not exist (or is unreachable) on the FTP server.","triggerScenarios":"Calling storageAdapter.NewReader(ctx, name) where s.conn.Retr(objectPath) returns an error matching FTP status 550/\"no such file\" patterns detected by isFTPNotFoundError.","commonSituations":"Typo in file name, wrong base path/prefix configured in buildPath, file deleted by another process, working directory differing from the expected FTP root, case-sensitivity mismatch on Unix FTP servers.","solutions":["Verify the exact object name and that the file exists: run an FTP LIST or call StatObject on the same name first","Check the base-path/prefix configuration used by buildPath — the effective path is baseDir + name","Remember FTP paths are case-sensitive on most servers; match the case exactly","Handle the not-found case with errors.Is(err, errObjectNotFound) instead of treating it as a transient failure"],"exampleFix":"// before\nr, err := store.NewReader(ctx, \"Data/report.csv\")\n// after\nr, err := store.NewReader(ctx, \"data/report.csv\")\nif err != nil && errors.Is(err, errObjectNotFound) { /* create default file or return 404 */ }","handlingStrategy":"try-catch","validationCode":"if _, err := store.StatObject(ctx, name); err != nil {\n    // object missing; handle before calling NewReader\n}","typeGuard":"func isFTPNotFound(err error) bool { return errors.Is(err, errObjectNotFound) }","tryCatchPattern":"r, err := store.NewReader(ctx, name)\nif err != nil {\n    if errors.Is(err, errObjectNotFound) {\n        return nil, ErrNotFound // map to 404\n    }\n    return nil, err\n}","preventionTips":["StatObject or LIST before reading when existence is uncertain","Verify base-path/prefix configuration once at startup","Match file-name case exactly; FTP is case-sensitive on Unix servers"],"tags":["ftp","file-not-found","storage"],"backgroundTag":"ftp-object-not-found","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}