{"record":{"id":"9ca456aa5d87ba3c","repo":"crowdsecurity/crowdsec","slug":"timeout-exceeded","errorCode":null,"errorMessage":"timeout exceeded","messagePattern":"timeout exceeded","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/csplugin/notifier.go","lineNumber":36,"sourceCode":"type GRPCClient struct{\n\tprotobufs.UnimplementedNotifierServer\n\tclient protobufs.NotifierClient \n}\n\nfunc (m *GRPCClient) Notify(ctx context.Context, notification *protobufs.Notification) (*protobufs.Empty, error) {\n\tdone := make(chan error)\n\tgo func() {\n\t\t_, err := m.client.Notify(\n\t\t\tctx, &protobufs.Notification{Text: notification.GetText(), Name: notification.GetName()},\n\t\t)\n\t\tdone <- err\n\t}()\n\tselect {\n\tcase err := <-done:\n\t\treturn &protobufs.Empty{}, err\n\n\tcase <-ctx.Done():\n\t\treturn &protobufs.Empty{}, errors.New(\"timeout exceeded\")\n\t}\n}\n\nfunc (m *GRPCClient) Configure(ctx context.Context, config *protobufs.Config) (*protobufs.Empty, error) {\n\t_, err := m.client.Configure(ctx, config)\n\treturn &protobufs.Empty{}, err\n}\n\ntype GRPCServer struct {\n\tImpl protobufs.NotifierServer\n}\n\nfunc (p *NotifierPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {\n\tprotobufs.RegisterNotifierServer(s, p.Impl)\n\treturn nil\n}\n\nfunc (*NotifierPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (any, error) {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/csplugin/notifier.go#L18-L54","documentation":"GRPCClient.Notify runs the plugin call in a goroutine and selects on the context. When ctx expires before the plugin responds (plugins run as separate subprocesses over gRPC and can be slow), Notify returns 'timeout exceeded'. It signals the caller that the notification was not delivered in time.","triggerScenarios":"A notification plugin binary that hangs, blocks on a slow network call (e.g. webhook to an unreachable host), or fails to respond within the context deadline passed to Notify.","commonSituations":"Plugin calling an external API behind a dead firewall; plugin binary crashed/hung; container host under load so the plugin subprocess starts slowly; default plugin timeout (5s from broker config) too short for a slow HTTP sink.","solutions":["Check the plugin process logs for hangs and test the plugin's external target (webhook URL, SMTP server) for reachability","Increase the plugin's 'timeout' setting in its config (defaults to 5s in the broker)","Restart crowdsec to respawn the plugin subprocess if it is stuck"],"exampleFix":"// before (plugin config.yaml)\nslack:\n  type: slack\n  webhook_url: https://hooks.slack.com/...\n\n// after\nslack:\n  type: slack\n  webhook_url: https://hooks.slack.com/...\n  timeout: 30s","handlingStrategy":"retry","validationCode":"ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel() // allow slow plugins a generous budget","typeGuard":null,"tryCatchPattern":"if _, err := client.Notify(ctx, req); err != nil {\n    if ctx.Err() == context.DeadlineExceeded || strings.Contains(err.Error(), \"timeout exceeded\") {\n        log.Warn(\"plugin notification timed out; will retry\")\n        return retryNotify(req)\n    }\n    return err\n}","preventionTips":["Set a plugin timeout larger than the plugin's worst-case external call","Monitor the plugin's external targets (webhook endpoints) for latency","Check plugin subprocess health after deployments"],"tags":["timeout","plugins","grpc"],"backgroundTag":"request-timeout","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}