grpc/grpc-go · error

requires SecurityLevel %v; connection has %v

Error message

requires SecurityLevel %v; connection has %v

What it means

Returned by credentials.CheckSecurityLevel when the established connection's CommonAuthInfo.SecurityLevel is below the requested level (credentials.go:302). Levels are ordered NoSecurity < IntegrityOnly < PrivacyAndIntegrity. It is the guard per-RPC credential implementations use to refuse sending secrets over an insufficiently protected transport.

Source

Thrown at credentials/credentials.go:303

// CheckSecurityLevel checks if a connection's security level is greater than or equal to the specified one.
// It returns success if 1) the condition is satisfied or 2) AuthInfo struct does not implement GetCommonAuthInfo() method
// or 3) CommonAuthInfo.SecurityLevel has an invalid zero value. For 2) and 3), it is for the purpose of backward-compatibility.
//
// This API is experimental.
func CheckSecurityLevel(ai AuthInfo, level SecurityLevel) error {
	type internalInfo interface {
		GetCommonAuthInfo() CommonAuthInfo
	}
	if ai == nil {
		return errors.New("AuthInfo is nil")
	}
	if ci, ok := ai.(internalInfo); ok {
		// CommonAuthInfo.SecurityLevel has an invalid value.
		if ci.GetCommonAuthInfo().SecurityLevel == InvalidSecurityLevel {
			return nil
		}
		if ci.GetCommonAuthInfo().SecurityLevel < level {
			return fmt.Errorf("requires SecurityLevel %v; connection has %v", level, ci.GetCommonAuthInfo().SecurityLevel)
		}
	}
	// The condition is satisfied or AuthInfo struct does not implement GetCommonAuthInfo() method.
	return nil
}

// ChannelzSecurityInfo defines the interface that security protocols should implement
// in order to provide security info to channelz.
//
// This API is experimental.
type ChannelzSecurityInfo interface {
	GetSecurityValue() ChannelzSecurityValue
}

// ChannelzSecurityValue defines the interface that GetSecurityValue() return value
// should satisfy. This interface should only be satisfied by *TLSChannelzSecurityValue
// and *OtherChannelzSecurityValue.
//

View on GitHub (pinned to 03255a9237)

Solutions

  1. Use TLS or ALTS transport credentials on the channel so AuthInfo.SecurityLevel >= PrivacyAndIntegrity.
  2. If using a custom TransportCredentials, embed CommonAuthInfo{SecurityLevel: PrivacyAndIntegrity} in the returned AuthInfo.
  3. For local dev where TLS is not possible, do not attach per-RPC credentials that RequireTransportSecurity().
  4. Call CheckSecurityLevel yourself with the exact level you need to fail fast with a clearer message.

Example fix

// before: per-RPC creds over insecure transport
conn, _ := grpc.NewClient(addr,
    grpc.WithTransportCredentials(insecure.NewCredentials()),
    grpc.WithPerRPCCredentials(tokenCreds),
)

// after: TLS so security level satisfies PrivacyAndIntegrity
conn, _ := grpc.NewClient(addr,
    grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
    grpc.WithPerRPCCredentials(tokenCreds),
)
Defensive patterns

Strategy: validation

Validate before calling

// Verify the security level before relying on the connection.
if err := credentials.CheckSecurityLevel(authInfo, credentials.PrivacyAndIntegrity); err != nil {
    return fmt.Errorf("channel is not sufficiently secure: %w", err)
}

Type guard

// Confirm AuthInfo carries a usable CommonAuthInfo.
func hasSecurityLevel(ai credentials.AuthInfo) bool {
    type common interface{ GetCommonAuthInfo() credentials.CommonAuthInfo }
    c, ok := ai.(common)
    return ok && c.GetCommonAuthInfo().SecurityLevel >= credentials.PrivacyAndIntegrity
}

Try / catch

if err := credentials.CheckSecurityLevel(ri.AuthInfo, want); err != nil {
    // configuration error, not transient: fix the channel's transport credentials.
    return fmt.Errorf("refusing to send credentials: %w", err)
}

Prevention

When it happens

Trigger: A PerRPCCredentials implementation calls CheckSecurityLevel(ai, PrivacyAndIntegrity) but the channel was built with insecure.NewCredentials() (NoSecurity) or an integrity-only scheme. The AuthInfo embedded a SecurityLevel below the required one. Also reachable directly from user code calling CheckSecurityLevel on server-side AuthInfo.

Common situations: Using oauth/JWT/ALTS per-RPC credentials on a grpc.WithTransportCredentials(insecure.NewCredentials()) channel; mixing a TLS-requiring call cred with a plaintext dev channel; or a custom TransportCredentials whose AuthInfo forgot to set SecurityLevel to PrivacyAndIntegrity.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/675f42d49c5a0d1d. Report an issue: GitHub.