gofr-dev/gofr · error
FTP login failed for user %q: %w
Error message
FTP login failed for user %q: %w
What it means
This error wraps the failure of the FTP LOGIN command after a successful dial. The server was reachable but rejected the credentials for the configured user. The adapter closes the connection (Quit) before returning, so the returned error is the only diagnostic.
Source
Thrown at pkg/gofr/datasource/file/ftp/storage_adapter.go:82
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
}
if s.conn == nil {
return nil, errFTPClientNotInitialized
}
objectPath := s.buildPath(name)View on GitHub (pinned to 187eb24962)
Solutions
- Verify User and Password in the Config against the server's account store
- Test the same credentials with a manual FTP client (ftp/lftp) to isolate app vs credential issues
- Check whether the account is locked, expired, or IP-restricted on the server
- Ensure secrets are loaded from the right environment (dev vs prod) and not truncated
Example fix
// before
cfg := &ftp.Config{Host: h, Port: 21, User: "deploy", Password: oldPass}
// after
cfg := &ftp.Config{Host: h, Port: 21, User: "deploy", Password: os.Getenv("FTP_PASSWORD")} Defensive patterns
Strategy: validation
Validate before calling
// fail fast on missing credentials before Connect
if cfg.User == "" || cfg.Password == "" {
return errors.New("ftp credentials missing: set FTP_USER and FTP_PASSWORD")
} Type guard
func isLoginError(err error) bool { return strings.Contains(err.Error(), "FTP login failed") } Try / catch
err := fs.Connect(cfg)
if strings.Contains(err.Error(), "FTP login failed") {
// do not blindly retry — check credentials/account status first
return fmt.Errorf("check FTP credentials: %w", err)
} Prevention
- Load credentials from a secret manager; never hardcode or commit passwords
- Rotate secrets in lockstep with the FTP server account store
- Test credentials manually with lftp/ftp when provisioning a new environment
- Limit login retries to avoid account lockout; alert on repeated auth failures
When it happens
Trigger: Calling Connect when cfg.User/cfg.Password are wrong, the account is disabled or expired, the server requires TLS/auth not negotiated, or the user is not permitted from the client's IP.
Common situations: Rotated passwords not updated in env/config; anonymous FTP disabled while using user 'anonymous' or empty credentials; account locked after failed attempts; IP allowlist on the FTP server blocking the caller.
Related errors
- invalid Azure configuration: account key is required
- invalid FTP configuration: host and port are required
- invalid FTP provider
- FTP config is nil
- FTP client is not initialized
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/b60a4d15a1dcf639.
Report an issue: GitHub.