Errors returned by Dial, and errors that arrive later¶
Because Dial builds a lazy connection, failures split into two groups: the few Dial
itself can catch, and the many that only surface on the first RPC. Looking in the wrong
group is the usual reason a failure seems to have no cause.
Everything Dial can fail on¶
Dial returns an error in exactly two situations, and both are wrapped with
github.com/cockroachdb/errors so the cause is preserved for errors.Is and
errors.As.
build gRPC client TLS credentials: …¶
The TLS material named by Target.TLS.Cert could not be turned into a certificate pool.
Target.TLS.Enabled must be true for this to be reachable — with TLS disabled, Cert
is never read.
| Cause | Message |
|---|---|
| File does not exist | build gRPC client TLS credentials: reading CA file "/etc/pki/ca.pem": open /etc/pki/ca.pem: no such file or directory |
| Path is a directory | build gRPC client TLS credentials: reading CA file "/etc/pki": read /etc/pki: is a directory |
| File contains no PEM certificate | build gRPC client TLS credentials: no certificates found in "/etc/pki/ca.pem" |
| File unreadable by this process | build gRPC client TLS credentials: reading CA file "…": open …: permission denied |
"No certificates found" is the one that catches people: the file exists and was read, but
nothing in it parsed as a CERTIFICATE PEM block. A DER-encoded .crt, a PKCS#12
bundle, or a file containing only a private key all land here.
dial gRPC target "host:port": …¶
grpc.NewClient rejected the endpoint or the options. In practice there are three causes.
| Cause | Message |
|---|---|
Endpoint is unparseable — a control character or a malformed URI in Target.Host |
dial gRPC target "\x7f:1": … |
grpc.WithCredentialsBundle passed as an option |
dial gRPC target "localhost:1": grpc: credentials.Bundle may not be used with individual TransportCredentials |
grpc.WithPerRPCCredentials passed while Target.TLS.Enabled is false |
dial gRPC target "localhost:1": grpc: the credentials require transport level security (use grpc.WithTransportCredentials() to set) |
The last one is a safety check in the gRPC SDK, not in this module: token credentials
refuse to be sent over a plaintext connection. Enable TLS on the Target rather than
working around it.
What Dial never fails on¶
None of these produce an error from Dial. Each one returns a usable-looking
*grpc.ClientConn and fails at the first RPC:
- A port of
0, a negative port, or a port above 65535. - A host that does not resolve.
- A host that is a gRPC target URI (
dns:///svc) or carries a scheme (https://svc). - An unbracketed IPv6 literal (
::1rather than[::1]). - A server that is not running, or not speaking gRPC.
- TLS enabled against a plaintext server, or the reverse.
- A certificate that does not match the host.
If you need any of these caught early, validate the Target before you build it, or call
conn.Connect() and wait on conn.WaitForStateChange before declaring the client
healthy.
Failures that arrive at the first RPC¶
All of these come back as a codes.Unavailable status from the call, not from Dial.
connection refused¶
rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp 127.0.0.1:41274: connect: connection refused"
Nothing is listening on that host and port. Check Target.Port, and remember that an
empty Target.Host means localhost — not the server you were thinking of.
first record does not look like a TLS handshake¶
rpc error: code = Unavailable desc = connection error: desc = "transport: authentication handshake failed: tls: first record does not look like a TLS handshake"
Target.TLS.Enabled is true but the server is speaking plaintext gRPC. Either the
server has TLS switched off, or you are talking to the wrong port.
certificate is valid for X, not Y¶
rpc error: code = Unavailable desc = connection error: desc = "transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate is valid for svc.internal, not localhost"
The certificate does not name Target.Host. Set Host to a name the certificate covers,
or pass grpc.WithAuthority to verify against a different name — see
Verifying a certificate under a different name.
x509: certificate signed by unknown authority¶
rpc error: code = Unavailable desc = connection error: desc = "transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate signed by unknown authority"
The chain does not reach a trust anchor. With TLS.Cert empty you are trusting the system
roots only; with TLS.Cert set you are trusting only that file, because
gtls.ClientConfig replaces RootCAs rather than extending it. Point Cert at the CA
that issued the server's certificate, and include intermediates if the server does not
send them.
remote error: tls: certificate required¶
rpc error: code = Unavailable desc = connection error: desc = "error reading server preface: remote error: tls: certificate required"
The server requires a client certificate and Dial never sends one, whatever you put in
Target.TLS.Key. This module cannot do mutual TLS — see
What grpcclient does not do.
invalid target address … too many colons in address¶
rpc error: code = Unavailable desc = invalid target address ::1:37225, error info: address ::1:37225:443: too many colons in address
An IPv6 literal was passed unbracketed. Set Host to [::1] rather than ::1.
circuit breaker is open¶
This one is not from grpcclient. It comes from go/transit's
CircuitBreakerInterceptor, which you passed as a dial option, after the configured
number of consecutive failures. It is deliberately indistinguishable from a real outage on
the wire. Fix the underlying failures — the codes above — rather than the breaker.