{"record":{"id":"c6af59276a8923e0","repo":"grpc/grpc-go","slug":"errcodeenhanceyourcalm","errorCode":"ErrCodeEnhanceYourCalm","errorMessage":"too_many_pings","messagePattern":"too_many_pings","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/transport/http2_server.go","lineNumber":924,"sourceCode":"\tt.mu.Lock()\n\tns := len(t.activeStreams)\n\tt.mu.Unlock()\n\tif ns < 1 && !t.kep.PermitWithoutStream {\n\t\t// Keepalive shouldn't be active thus, this new ping should\n\t\t// have come after at least defaultPingTimeout.\n\t\tif t.lastPingAt.Add(defaultPingTimeout).After(now) {\n\t\t\tt.pingStrikes++\n\t\t}\n\t} else {\n\t\t// Check if keepalive policy is respected.\n\t\tif t.lastPingAt.Add(t.kep.MinTime).After(now) {\n\t\t\tt.pingStrikes++\n\t\t}\n\t}\n\n\tif t.pingStrikes > maxPingStrikes {\n\t\t// Send goaway and close the connection.\n\t\tt.controlBuf.put(&goAway{code: http2.ErrCodeEnhanceYourCalm, debugData: []byte(\"too_many_pings\"), closeConn: errors.New(\"got too many pings from the client\")})\n\t}\n}\n\nfunc (t *http2Server) handleWindowUpdate(f *http2.WindowUpdateFrame) {\n\tt.controlBuf.put(&incomingWindowUpdate{\n\t\tstreamID:  f.Header().StreamID,\n\t\tincrement: f.Increment,\n\t})\n}\n\nfunc appendHeaderFieldsFromMD(headerFields []hpack.HeaderField, md metadata.MD) []hpack.HeaderField {\n\tfor k, vv := range md {\n\t\tif isReservedHeader(k) {\n\t\t\t// Clients don't tolerate reading restricted headers after some non restricted ones were sent.\n\t\t\tcontinue\n\t\t}\n\t\tfor _, v := range vv {\n\t\t\theaderFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)})","sourceCodeStart":906,"sourceCodeEnd":942,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/transport/http2_server.go#L906-L942","documentation":"Sent as an HTTP/2 GOAWAY frame with code ENHANCE_YOUR_CALM when the server's keepalive enforcement detects the client is sending PING frames too frequently (more than maxPingStrikes=2 strikes). The server tracks ping strikes when pings arrive faster than the configured keepalive policy interval (MinTime, or defaultPingTimeout when no streams are active and PermitWithoutStream is false). After exceeding 2 strikes, the server sends this GOAWAY and closes the connection.","triggerScenarios":"A client sends HTTP/2 PING frames more frequently than the server's keepalive policy allows. Each out-of-policy ping increments pingStrikes; when it exceeds maxPingStrikes (2), the server at http2_server.go:922-924 sends GOAWAY(EnhanceYourCalm, 'too_many_pings') and closes the connection. This commonly occurs with aggressive client-side keepalive settings.","commonSituations":"Client configured with keepalive.Time too low (e.g., 1s) hitting a server with a higher MinTime (default ~5min for gRPC servers, or 2h defaultPingTimeout without streams); client keepalive with PermitWithoutStream enabled sending pings during idle; a misbehaving or non-gRPC HTTP/2 client; multiple clients behind a load balancer multiplexing onto one connection with aggressive pings.","solutions":["Align client keepalive.Time to be >= server keepalive enforcement MinTime (server default is 5 minutes if configured, or 2 hours without streams).","Disable client keepalive.PermitWithoutStream if the server doesn't permit pings without active streams, or ensure pings only happen when streams exist.","Configure the server's keepalive enforcement policy (grpc.KeepaliveEnforcementPolicy) with a MinTime that accommodates your clients, and set PermitWithoutStream=true if needed.","Check for buggy HTTP/2 clients or proxies that send excessive pings."],"exampleFix":"// Client side: align keepalive with server policy\n// before (too aggressive)\nconn, _ := grpc.Dial(addr,\n    grpc.WithKeepaliveParams(keepalive.ClientParameters{\n        Time:                1 * time.Second, // too frequent!\n        PermitWithoutStream: true,\n    }),\n)\n// after (respect server's enforcement policy)\nconn, _ := grpc.Dial(addr,\n    grpc.WithKeepaliveParams(keepalive.ClientParameters{\n        Time:                30 * time.Second, // >= server MinTime\n        Timeout:             10 * time.Second,\n        PermitWithoutStream: false,\n    }),\n)","handlingStrategy":"validation","validationCode":"// Align client keepalive with server enforcement policy.\n// Validate before dialing:\nkp := keepalive.ClientParameters{\n    Time:                30 * time.Second, // must be >= server MinTime\n    Timeout:             10 * time.Second,\n    PermitWithoutStream: false,\n}\nconn, err := grpc.Dial(addr, grpc.WithKeepaliveParams(kp))","typeGuard":null,"tryCatchPattern":"// Retry on connection close due to too_many_pings with adjusted keepalive.\nerr := client.Call(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"too_many_pings\") {\n    log.Print(\"server rejected pings; increasing keepalive interval\")\n    // reconnect with less aggressive keepalive\n    conn.Close()\n    conn = reconnectWithKeepalive(60 * time.Second)\n}","preventionTips":["Set client keepalive.Time to be >= server's KeepaliveEnforcementPolicy.MinTime.","Avoid setting very low keepalive intervals (e.g., < 10s) unless the server permits it.","Coordinate client and server keepalive policies across your fleet.","Monitor for GOAWAY/EnhanceYourCalm events as a signal of policy mismatch."],"tags":["transport","http2","keepalive","connection-close","grpc","network"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}