gofr-dev/gofr · error
%w %q: %w
Error message
%w %q: %w
What it means
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.
Source
Thrown at pkg/gofr/datasource/file/ftp/storage_adapter.go:105
return nil
}
// NewReader creates a reader for the given object.
func (s *storageAdapter) NewReader(_ context.Context, name string) (io.ReadCloser, error) {
if name == "" {
return nil, errEmptyObjectName
}
if s.conn == nil {
return nil, errFTPClientNotInitialized
}
objectPath := s.buildPath(name)
reader, err := s.conn.Retr(objectPath)
if err != nil {
if isFTPNotFoundError(err) {
return nil, fmt.Errorf("%w %q: %w", errObjectNotFound, name, err)
}
return nil, fmt.Errorf("%w for %q: %w", errFailedToCreateReader, name, err)
}
return reader, nil
}
// NewRangeReader creates a range reader for the given object.
func (s *storageAdapter) NewRangeReader(_ context.Context, name string, offset, length int64) (io.ReadCloser, error) {
if name == "" {
return nil, errEmptyObjectName
}
if offset < 0 {
return nil, fmt.Errorf("%w (got: %d)", errInvalidOffset, offset)
}
View on GitHub (pinned to 187eb24962)
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
Example fix
// before
r, err := store.NewReader(ctx, "Data/report.csv")
// after
r, err := store.NewReader(ctx, "data/report.csv")
if err != nil && errors.Is(err, errObjectNotFound) { /* create default file or return 404 */ } Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := store.StatObject(ctx, name); err != nil {
// object missing; handle before calling NewReader
} Type guard
func isFTPNotFound(err error) bool { return errors.Is(err, errObjectNotFound) } Try / catch
r, err := store.NewReader(ctx, name)
if err != nil {
if errors.Is(err, errObjectNotFound) {
return nil, ErrNotFound // map to 404
}
return nil, err
} Prevention
- 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
When it happens
Trigger: Calling storageAdapter.NewReader(ctx, name) where s.conn.Retr(objectPath) returns an error matching FTP status 550/"no such file" patterns detected by isFTPNotFoundError.
Common situations: 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.
Related errors
- %w: %q
- failed to create directory %q: %w
- invalid FTP configuration: host and port are required
- invalid FTP provider
- FTP config is nil
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/5731ba300987a75d.
Report an issue: GitHub.