gofr-dev/gofr · error
%w for %q: %w
Error message
%w for %q: %w
What it means
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).
Source
Thrown at pkg/gofr/datasource/file/ftp/storage_adapter.go:108
// 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)
}
if s.conn == nil {
return nil, errFTPClientNotInitialized
}View on GitHub (pinned to 187eb24962)
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
Example fix
// before
r, err := store.NewReader(ctx, "data/report.csv") // fails after idle timeout
// after
if err := ftpConn.Close(); err != nil { }
ftpConn, _ = ftp.DialAndLogin(...) // re-dial before retrying
r, err := store.NewReader(ctx, "data/report.csv") Defensive patterns
Strategy: retry
Validate before calling
if store == nil || ftpConn == nil {
return errors.New("ftp client not initialized")
} Type guard
func isFTPNotFound(err error) bool { return errors.Is(err, errObjectNotFound) } Try / catch
r, err := store.NewReader(ctx, name)
if err != nil && !errors.Is(err, errObjectNotFound) {
// transient: reconnect FTP and retry with backoff
r, err = retryWithBackoff(3, func() (io.ReadCloser, error) { return store.NewReader(ctx, name) })
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- failed to create reader
- failed to list objects
- failed to dial FTP server %q: %w
- %w for %q at offset %d: %w
- failed to read source object %q: %w
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/3bd8123df446c8e8.
Report an issue: GitHub.