{"record":{"id":"ee423471703bbc5a","repo":"go-kratos/kratos","slug":"ratelimit","errorCode":"RATELIMIT","errorMessage":"service unavailable due to rate limit exceeded","messagePattern":"service unavailable due to rate limit exceeded","errorType":"http","errorClass":"github.com/go-kratos/kratos/v3/errors.Error","httpStatus":429,"severity":"error","filePath":"contrib/polaris/ratelimit.go","lineNumber":18,"sourceCode":"package polaris\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/go-kratos/kratos/v3/errors\"\n\t\"github.com/go-kratos/kratos/v3/middleware\"\n\t\"github.com/go-kratos/kratos/v3/middleware/ratelimit\"\n\t\"github.com/go-kratos/kratos/v3/transport\"\n\t\"github.com/go-kratos/kratos/v3/transport/http\"\n\n\t\"github.com/polarismesh/polaris-go/pkg/model\"\n)\n\n// ErrLimitExceed is service unavailable due to rate limit exceeded.\nvar (\n\tErrLimitExceed = errors.New(429, \"RATELIMIT\", \"service unavailable due to rate limit exceeded\")\n)\n\n// Ratelimit Request rate limit middleware\nfunc Ratelimit(l Limiter) middleware.Middleware {\n\treturn func(handler middleware.Handler) middleware.Handler {\n\t\treturn func(ctx context.Context, req any) (reply any, err error) {\n\t\t\tif tr, ok := transport.FromServerContext(ctx); ok {\n\t\t\t\tvar args []model.Argument\n\t\t\t\theaders := tr.RequestHeader()\n\t\t\t\t// handle header\n\t\t\t\tfor _, header := range headers.Keys() {\n\t\t\t\t\targs = append(args, model.BuildHeaderArgument(header, headers.Get(header)))\n\t\t\t\t}\n\t\t\t\t// handle http\n\t\t\t\tif ht, ok := tr.(*http.Transport); ok {\n\t\t\t\t\t// url query\n\t\t\t\t\tfor key, values := range ht.Request().URL.Query() {\n\t\t\t\t\t\targs = append(args, model.BuildQueryArgument(key, strings.Join(values, \",\")))","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/go-kratos/kratos/blob/668db92c2c001e9552594ba5a8aede8456af6d7e/contrib/polaris/ratelimit.go#L1-L36","documentation":"ErrLimitExceed is a typed kratos error (HTTP 429, reason RATELIMIT) defined in contrib/polaris/ratelimit.go:18 and returned by the polaris Ratelimit middleware. Inside the middleware, l.Allow(operation, args...) is called with the operation plus header/query arguments built from the request; if Allow returns an error (polaris quota denied), the middleware aborts the handler and returns ErrLimitExceed without executing business logic.","triggerScenarios":"Attaching polaris.Ratelimit(l) as server middleware and receiving traffic that exceeds the quota rule configured in polaris for that operation/route; Allow also returns an error for any polaris quota API failure, so a broken polaris server connection can surface the same error. Client sees a 429 whose body encodes reason RATELIMIT.","commonSituations":"Load test or traffic spike tripping a polaris rate rule; rule configured per-header/per-query argument (the middleware forwards all headers and URL queries as model.Argument) so a specific caller is throttled; polaris server unreachable so every Allow fails and all requests appear rate-limited.","solutions":["Client side: honor the 429, back off and retry with jitter instead of hammering","Check the polaris console rate-limit rules for the operation and adjust the quota if the limit is genuinely too low","Verify polaris server connectivity from the app - Allow errors on infra failure look identical to real rejections","Match precisely with kratos errors: if e := errors.FromError(err); e.Reason == \"RATELIMIT\" && e.Code == 429"],"exampleFix":"// client-side handling\nreply, err := client.Call(ctx, req)\nif e := kerrors.FromError(err); e.Code == 429 && e.Reason == \"RATELIMIT\" {\n    time.Sleep(backoff()) // exponential + jitter, then retry\n    reply, err = client.Call(ctx, req)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if reply, err = handler(ctx, req); err != nil {\n    if e := kerrors.FromError(err); e.Code == 429 && e.Reason == \"RATELIMIT\" {\n        // quota denied: back off and retry with jitter; do not retry immediately\n    }\n}","preventionTips":["Size polaris quota rules for peak traffic plus headroom before enabling the middleware","Differentiate infra failure from real rejection by monitoring polaris server health - Allow errors on both map to ErrLimitExceed","Clients: implement exponential backoff with jitter and honor Retry-After style guidance","Test rate rules in a staging namespace before applying to production"],"tags":["middleware","polaris","rate-limit","http-429"],"backgroundTag":null,"analyzedSha":"668db92c2c001e9552594ba5a8aede8456af6d7e","analyzedAt":"2026-08-16T02:07:20.704Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}