gofr-dev/gofr · error
failed to dial FTP server %q: %w
Error message
failed to dial FTP server %q: %w
What it means
This error wraps the goftp dial failure when Connect cannot establish a TCP connection to the FTP server at host:port. It uses %w so the root cause (DNS failure, connection refused, timeout) is preserved for errors.Is/As inspection. No login has been attempted at this point.
Source
Thrown at pkg/gofr/datasource/file/ftp/storage_adapter.go:77
if s.cfg == nil {
return errFTPConfigNil
}
if s.cfg.Host == "" || s.cfg.Port <= 0 {
return errFTPConfigInvalid
}
// Set default timeout if not specified
dialTimeout := s.cfg.DialTimeout
if dialTimeout == 0 {
dialTimeout = 5 * time.Second
}
ftpServer := fmt.Sprintf("%s:%d", s.cfg.Host, s.cfg.Port)
conn, err := ftp.Dial(ftpServer, ftp.DialWithTimeout(dialTimeout))
if err != nil {
return fmt.Errorf("failed to dial FTP server %q: %w", ftpServer, err)
}
if err := conn.Login(s.cfg.User, s.cfg.Password); err != nil {
_ = conn.Quit()
return fmt.Errorf("FTP login failed for user %q: %w", s.cfg.User, err)
}
s.conn = conn
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
}
View on GitHub (pinned to 187eb24962)
Solutions
- Verify the server is reachable: nc -vz host port (or telnet) from the same network
- Correct Host and Port in the Config
- Check firewall/security-group egress rules allow outbound TCP to the FTP port
- Retry with backoff for transient network outages; inspect the wrapped cause via errors.Unwrap
Example fix
// before
cfg := &ftp.Config{Host: "ftp.internal", Port: 2121} // wrong port
// after
cfg := &ftp.Config{Host: "ftp.internal", Port: 21}
if err := fs.Connect(cfg); err != nil {
return fmt.Errorf("connect: %w", err) // unwrap to see dial cause
} Defensive patterns
Strategy: retry
Validate before calling
// pre-flight reachability check before Connect
host, port := cfg.Host, cfg.Port
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), 5*time.Second)
if err != nil { return fmt.Errorf("ftp server unreachable: %w", err) }
_ = conn.Close() Type guard
func isDialError(err error) bool {
return strings.HasPrefix(err.Error(), "failed to dial FTP server") || errors.Is(err, net.ErrUnknownNetwork) || errors.Is(err, os.ErrDeadlineExceeded)
} Try / catch
err := fs.Connect(cfg)
var netErr net.Error
if errors.As(err, &netErr) || strings.Contains(err.Error(), "failed to dial") {
// retry with exponential backoff; check host/port/firewall if persistent
} Prevention
- Verify DNS resolution and port with a TCP probe before depending on the service
- Open firewall/security-group egress to the FTP control port
- Use retries with backoff for transient outages
- Keep dial timeouts modest so failures surface quickly with a clear cause
When it happens
Trigger: Calling Connect when the server hostname does not resolve, the port is wrong, the server is down, or the dial exceeds the configured dialTimeout.
Common situations: Wrong host/port in config; FTP service not running or blocked by security groups/firewall; DNS misconfiguration in containers/K8s; network egress restrictions from the runtime environment.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- %w: creating index: %w
- %w: deleting index: %w
- %w: executing search: %w
- %w: executing bulk: %w
- FTP client is not initialized
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/1e0cc05904b72149.
Report an issue: GitHub.