grpc/grpc-go · error
local credentials rejected connection to non-local address %
Error message
local credentials rejected connection to non-local address %q
What it means
Thrown by getSecurityLevel in local/local.go:82 when the remote address is not recognized as a local connection (loopback 127.* or [::1]:, a Windows named pipe, or a unix-domain socket). local.NewCredentials() infers the security level purely from the connection type and refuses to run on non-local transports because it would otherwise imply a security guarantee it cannot provide.
Source
Thrown at credentials/local/local.go:82
return c.info
}
// getSecurityLevel returns the security level for a local connection.
// It returns an error if a connection is not local.
func getSecurityLevel(network, addr string) (credentials.SecurityLevel, error) {
switch {
// Local TCP connection
case strings.HasPrefix(addr, "127."), strings.HasPrefix(addr, "[::1]:"):
return credentials.NoSecurity, nil
// Windows named pipe connection
case network == "pipe" && strings.HasPrefix(addr, `\\.\pipe\`):
return credentials.NoSecurity, nil
// UDS connection
case network == "unix":
return credentials.PrivacyAndIntegrity, nil
// Not a local connection and should fail
default:
return credentials.InvalidSecurityLevel, fmt.Errorf("local credentials rejected connection to non-local address %q", addr)
}
}
func (*localTC) ClientHandshake(_ context.Context, _ string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
secLevel, err := getSecurityLevel(conn.RemoteAddr().Network(), conn.RemoteAddr().String())
if err != nil {
return nil, nil, err
}
return conn, info{credentials.CommonAuthInfo{SecurityLevel: secLevel}}, nil
}
func (*localTC) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
secLevel, err := getSecurityLevel(conn.RemoteAddr().Network(), conn.RemoteAddr().String())
if err != nil {
return nil, nil, err
}
return conn, info{credentials.CommonAuthInfo{SecurityLevel: secLevel}}, nil
}View on GitHub (pinned to 03255a9237)
Solutions
- Use TLS (credentials.NewClientTLSFromFile / NewTLS) for any non-loopback, non-UDS destination.
- Ensure the dial target really is loopback (127.0.0.1 / localhost / [::1]) or a unix: scheme address when using local creds.
- If you must keep plaintext over the wire, use insecure credentials explicitly — but only for non-sensitive traffic.
Example fix
// before
conn, _ := grpc.NewClient("10.0.0.5:50051",
grpc.WithTransportCredentials(local.NewCredentials()),
)
// after
conn, _ := grpc.NewClient("10.0.0.5:50051",
grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(caPool, "10.0.0.5")),
) Defensive patterns
Strategy: validation
Validate before calling
func isLocalTarget(addr string) bool {
h, _, _ := net.SplitHostPort(addr)
h = strings.ToLower(h)
return h == "" || strings.HasPrefix(addr, "127.") || strings.HasPrefix(addr, "[::1]:") ||
h == "localhost" || strings.HasPrefix(addr, "unix:") || strings.HasPrefix(addr, "\\\\\\\\.\\pipe\\\\")
}
if !isLocalTarget(addr) {
creds = credentials.NewClientTLSFromCert(caPool, "") // use TLS, not local.NewCredentials()
} Try / catch
// Connection-time error from ClientHandshake/ServerHandshake:
if strings.Contains(err.Error(), "non-local address") {
// switch dial target to loopback/UDS or switch to TLS credentials
} Prevention
- Reserve local.NewCredentials() strictly for 127.0.0.1/[::1]/unix targets.
- Bind dev listeners to 127.0.0.1, not 0.0.0.0, when using local creds.
- Add a startup assertion that remote addresses use TLS credentials.
When it happens
Trigger: Calling grpc.WithTransportCredentials(local.NewCredentials()) against a remote host (e.g. 10.0.0.5:50051 or a DNS name resolving off-box), or a unix socket path that dialer resolved to a TCP address. Fires on both ClientHandshake (line 87) and ServerHandshake (line 95).
Common situations: Promoting a local-only prototype to a real network address without swapping local creds for TLS; a test that uses local creds but dials an in-process listener bound to 0.0.0.0; misconfigured UDS address that the resolver maps to TCP.
Related errors
- cannot send secure credentials on an insecure connection: %v
- unable to transfer TokenSource PerRPCCredentials: %v
- unable to transfer jwtAccess PerRPCCredentials: %v
- unable to transfer oauthAccess PerRPCCredentials: %v
- unable to transfer serviceAccount PerRPCCredentials: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/fb1d62310aad0b00.
Report an issue: GitHub.