larksuite/cli · error
nil connection
Error message
nil connection
What it means
validateConnRemoteIP performs the post-dial SSRF check by inspecting the connection's remote address. It throws this error when the net.Conn handed to it is nil, meaning no connection object exists to validate. This is a defensive guard so the validator never dereferences a nil connection.
Source
Thrown at internal/validate/url.go:549
func dialConn(ctx context.Context, dialFn func(context.Context, string, string) (net.Conn, error), network, addr string) (net.Conn, error) {
if dialFn != nil {
return dialFn(ctx, network, addr)
}
var d net.Dialer
return d.DialContext(ctx, network, addr)
}
func downloadTargetPolicyError(err error) error {
return errs.NewSecurityPolicyError(
errs.SubtypeAccessDenied,
"blocked download target: %v",
err,
).WithCause(err)
}
func validateConnRemoteIP(conn net.Conn) error {
if conn == nil {
return fmt.Errorf("nil connection")
}
raddr := conn.RemoteAddr()
if raddr == nil {
return fmt.Errorf("missing remote address")
}
host, _, err := net.SplitHostPort(raddr.String())
if err != nil {
host = raddr.String()
}
ip := net.ParseIP(strings.Trim(host, "[]"))
if ip == nil {
return fmt.Errorf("invalid remote IP")
}
if isRestrictedDownloadIP(ip) {
return fmt.Errorf("local/internal host is not allowed")
}
return nil
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Ensure the dial result is checked: if err != nil return err before validating the conn
- Never call validateConnRemoteIP with a conn from a failed dial
- If wrapping the dialer, propagate the dial error instead of continuing with a nil connection
Example fix
// before
conn, _ := dialer.DialContext(ctx, network, addr)
err := validateConnRemoteIP(conn) // nil conn
// after
conn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
err = validateConnRemoteIP(conn) Defensive patterns
Strategy: validation
Validate before calling
if conn == nil {
return fmt.Errorf("dial failed: no connection returned")
}
if err := validateConnRemoteIP(conn); err != nil { return err } Type guard
func dialAndValidate(ctx context.Context, d *net.Dialer, network, addr string) (net.Conn, error) {
conn, err := d.DialContext(ctx, network, addr)
if err != nil || conn == nil {
return nil, fmt.Errorf("dial %s: %w", addr, err)
}
return conn, validateConnRemoteIP(conn)
} Try / catch
if err != nil && strings.Contains(err.Error(), "nil connection") {
return fmt.Errorf("dialer returned no connection without an error — fix the custom dialer: %w", err)
} Prevention
- Always check the dial error before using the connection
- Never return (nil, nil) from custom DialContext wrappers
- Keep custom dialers thin: propagate conn and err verbatim
- Test custom dialers return a non-nil conn on success
When it happens
Trigger: The dialing helper returns (nil, nil) or the caller ignores the dial error and passes the nil conn to validateConnRemoteIP — typically from an anonymous wrapper around the dial-and-validate sequence.
Common situations: Custom DialContext wrappers that swallow dial errors; refactored dial paths returning a nil conn with a nil error; test doubles returning no connection.
Related errors
- missing remote address
- invalid remote IP
- local/internal host is not allowed
- blocked redirect target: %w
- download request URL is missing
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/16c2326bc4241848.
Report an issue: GitHub.