grpc/grpc-go · info
conn is not *net.TCPConn. got %T
Error message
conn is not *net.TCPConn. got %T
What it means
This error occurs in GetTCPUserTimeout when the provided net.Conn is not a *net.TCPConn. Unlike SetTCPUserTimeout (which silently returns nil for non-TCP conns), GetTCPUserTimeout explicitly errors. This is used to read the current TCP_USER_TIMEOUT value, typically for diagnostics/channelz.
Source
Thrown at internal/syscall/syscall_linux.go:95
rawConn, err := tcpconn.SyscallConn()
if err != nil {
return fmt.Errorf("error getting raw connection: %v", err)
}
err = rawConn.Control(func(fd uintptr) {
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond))
})
if err != nil {
return fmt.Errorf("error setting option on socket: %v", err)
}
return nil
}
// GetTCPUserTimeout gets the TCP user timeout on a connection's socket
func GetTCPUserTimeout(conn net.Conn) (opt int, err error) {
tcpconn, ok := conn.(*net.TCPConn)
if !ok {
err = fmt.Errorf("conn is not *net.TCPConn. got %T", conn)
return
}
rawConn, err := tcpconn.SyscallConn()
if err != nil {
err = fmt.Errorf("error getting raw connection: %v", err)
return
}
err = rawConn.Control(func(fd uintptr) {
opt, err = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT)
})
if err != nil {
err = fmt.Errorf("error getting option on socket: %v", err)
return
}
return
}
View on GitHub (pinned to 03255a9237)
Solutions
- If using Unix domain sockets, this error is expected and benign — TCP options don't apply.
- If you expect a TCP connection, verify the listener/dialer configuration isn't using a non-TCP transport.
- Suppress or ignore this error for non-TCP transports in diagnostic code paths.
Example fix
// before (broken): expecting TCP keepalive on a unix socket connection
lis, _ := net.Listen("unix", "/tmp/grpc.sock")
// GetTCPUserTimeout(conn) → "conn is not *net.TCPConn. got *net.UnixConn"
// after (valid): check connection type before calling
if _, ok := conn.(*net.TCPConn); ok {
timeout, err := syscall.GetTCPUserTimeout(conn)
// use timeout...
} else {
// non-TCP connection; TCP options not applicable
} Defensive patterns
Strategy: type-guard
Type guard
func isTCPConn(conn net.Conn) (*net.TCPConn, bool) {
tcp, ok := conn.(*net.TCPConn)
return tcp, ok
}
// Usage:
// if tcp, ok := isTCPConn(conn); ok {
// timeout, err := syscall.GetTCPUserTimeout(tcp)
// } Try / catch
if _, err := syscall.GetTCPUserTimeout(conn); err != nil {
if strings.Contains(err.Error(), "not *net.TCPConn") {
// expected for unix sockets or non-TCP transports; ignore
return
}
log.Printf("error reading TCP_USER_TIMEOUT: %v", err)
} Prevention
- Type-check the connection before calling GetTCPUserTimeout in diagnostic code.
- Expect this error for Unix domain socket and other non-TCP transports.
- Suppress benign non-TCP connection errors in metrics/diagnostic collection.
When it happens
Trigger: GetTCPUserTimeout is called with a net.Conn that is not *net.TCPConn — e.g., a unix socket connection, a TLS connection wrapper, or a custom net.Conn type. The type assertion fails and the error reports the actual concrete type.
Common situations: gRPC server configured with a Unix domain socket listener (unix:///path) where channelz or diagnostic code attempts to read TCP keepalive settings, or a custom transport that provides a non-TCP underlying connection.
Related errors
- error getting raw connection: %v
- error setting option on socket: %v
- error getting option on socket: %v
- failed to do connect handshake, response: %q
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/4e4118e8423e6d2b.
Report an issue: GitHub.