grpc/grpc-go · info
credentials: rawConn is dispatched out of gRPC
Error message
credentials: rawConn is dispatched out of gRPC
What it means
ErrConnDispatched (credentials/credentials.go:146-148) is a sentinel that a custom TransportCredentials implementation returns to signal that the rawConn has been handed off out of gRPC and the caller MUST NOT close it. It is not a failure — it is a control-flow signal used by proxy/forwarding credentials (e.g. http_proxy credentials) that take ownership of the underlying net.Conn.
Source
Thrown at credentials/credentials.go:148
}
// AuthorityValidator validates the authority used to override the `:authority`
// header. This is an optional interface that implementations of AuthInfo can
// implement if they support per-RPC authority overrides. It is invoked when the
// application attempts to override the HTTP/2 `:authority` header using the
// CallAuthority call option.
type AuthorityValidator interface {
// ValidateAuthority checks the authority value used to override the
// `:authority` header. The authority parameter is the override value
// provided by the application via the CallAuthority option. This value
// typically corresponds to the server hostname or endpoint the RPC is
// targeting. It returns non-nil error if the validation fails.
ValidateAuthority(authority string) error
}
// ErrConnDispatched indicates that rawConn has been dispatched out of gRPC
// and the caller should not close rawConn.
var ErrConnDispatched = errors.New("credentials: rawConn is dispatched out of gRPC")
// TransportCredentials defines the common interface for all the live gRPC wire
// protocols and supported transport security protocols (e.g., TLS, SSL).
type TransportCredentials interface {
// ClientHandshake does the authentication handshake specified by the
// corresponding authentication protocol on rawConn for clients. It returns
// the authenticated connection and the corresponding auth information
// about the connection. The auth information should embed CommonAuthInfo
// to return additional information about the credentials. Implementations
// must use the provided context to implement timely cancellation. gRPC
// will try to reconnect if the error returned is a temporary error
// (io.EOF, context.DeadlineExceeded or err.Temporary() == true). If the
// returned error is a wrapper error, implementations should make sure that
// the error implements Temporary() to have the correct retry behaviors.
// Additionally, ClientHandshakeInfo data will be available via the context
// passed to this call.
//
// The second argument to this method is the `:authority` header value usedView on GitHub (pinned to 03255a9237)
Solutions
- Treat ErrConnDispatched as a signal, not an error: the conn is now owned elsewhere — do not log/fail on it.
- When implementing such a credential, ensure you actually transfer ownership (start a reader/writer goroutine) before returning the sentinel, or you will leak the conn.
- If you did not intend to dispatch, return the real handshake error instead so gRPC closes rawConn.
- Unit-test that your credential returns this sentinel only on the intended code path.
Example fix
// before — custom cred hands off conn but returns a generic error (conn gets closed)
func (c *proxyCreds) ClientHandshake(ctx context.Context, a string, raw net.Conn) (net.Conn, credentials.AuthInfo, error) {
go forward(raw)
return nil, nil, errors.New("dispatched") // gRPC closes raw -> broken
}
// after — return the sentinel so gRPC leaves rawConn alone
func (c *proxyCreds) ClientHandshake(ctx context.Context, a string, raw net.Conn) (net.Conn, credentials.AuthInfo, error) {
go forward(raw)
return nil, nil, credentials.ErrConnDispatched
} Defensive patterns
Strategy: try-catch
Validate before calling
// When consuming a custom credential that may dispatch the conn,
// treat the sentinel as a signal, not an error
func dialWithProxy(target string) error {
_, _, err := creds.ClientHandshake(ctx, target, raw)
if errors.Is(err, credentials.ErrConnDispatched) {
return nil // conn ownership transferred; success
}
return err
} Type guard
func isConnDispatched(err error) bool {
return errors.Is(err, credentials.ErrConnDispatched)
} Try / catch
if errors.Is(err, credentials.ErrConnDispatched) {
// not a failure: rawConn is owned elsewhere; do not close it
} Prevention
- Recognize ErrConnDispatched as a control-flow signal, not an error.
- Only return it after truly transferring conn ownership (else you leak).
- Return the real error otherwise so gRPC closes rawConn.
When it happens
Trigger: A custom ClientHandshake/ServerHandshake returns (nil, nil, credentials.ErrConnDispatched) after forwarding/spawning a listener on rawConn. gRPC's transport code treats this sentinel specially to skip closing the connection it no longer owns.
Common situations: Implementing proxy-connect or in-process listener credentials (e.g. the gRPC xDS/proxy code paths); test doubles that move the conn; an accidentally-returned ErrConnDispatched from a buggy custom cred that then leaks the conn.
Related errors
- grpc: no transport security set (use grpc.WithTransportCrede
- grpc: credentials.Bundle may not be used with individual Tra
- grpc: credentials.Bundle must return non-nil transport crede
- grpc: the credentials require transport level security (use
- no alts.AuthInfo found in Peer
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/12055abafda736ab.
Report an issue: GitHub.