{"record":{"id":"2f6ad73ed64190fd","repo":"thanos-io/thanos","slug":"limit-v-violated-got-v","errorCode":null,"errorMessage":"limit %v violated (got %v)","messagePattern":"limit (.+?) violated \\(got (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/store/limiter.go","lineNumber":81,"sourceCode":"}\n\n// Reserve implements ChunksLimiter.\nfunc (l *Limiter) Reserve(num uint64) error {\n\treturn l.ReserveWithType(num, 0)\n}\n\nfunc (l *Limiter) ReserveWithType(num uint64, _ StoreDataType) error {\n\tif l == nil {\n\t\treturn nil\n\t}\n\tif l.limit == 0 {\n\t\treturn nil\n\t}\n\tif reserved := l.reserved.Add(num); reserved > l.limit {\n\t\t// We need to protect from the counter being incremented twice due to concurrency\n\t\t// while calling Reserve().\n\t\tl.failedOnce.Do(l.failedCounter.Inc)\n\t\treturn errors.Errorf(\"limit %v violated (got %v)\", l.limit, reserved)\n\t}\n\treturn nil\n}\n\n// NewChunksLimiterFactory makes a new ChunksLimiterFactory with a static limit.\nfunc NewChunksLimiterFactory(limit uint64) ChunksLimiterFactory {\n\treturn func(failedCounter prometheus.Counter) ChunksLimiter {\n\t\treturn NewLimiter(limit, failedCounter)\n\t}\n}\n\n// NewSeriesLimiterFactory makes a new SeriesLimiterFactory with a static limit.\nfunc NewSeriesLimiterFactory(limit uint64) SeriesLimiterFactory {\n\treturn func(failedCounter prometheus.Counter) SeriesLimiter {\n\t\treturn NewLimiter(limit, failedCounter)\n\t}\n}\n","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/store/limiter.go#L63-L99","documentation":"Limiter.ReserveWithType atomically increments the reserved counter and returns errors.Errorf(\"limit %v violated (got %v)\") when the reservation exceeds the configured static limit. Thanos uses these limiters (series/chunks limits) to protect the query path from unbounded memory usage.","triggerScenarios":"A StoreAPI Series response whose seriesCount (or chunks) would push the running total above the limit configured via NewBytesLimiter/NewChunksLimiterFactory (e.g. --store.series-limit / --store.chunk-limit flags).","commonSituations":"Queries selecting too many series hitting the series-limit; misconfigured (too low) limit flags; a burst of concurrent queries sharing one limiter factory exhausting the shared budget.","solutions":["Reduce query scope (fewer matchers, shorter time range) so fewer series are returned.","Raise the limit via the relevant flag (e.g. --store.series-limit) if it is intentionally too low.","Check concurrent queries sharing the limiter and stagger/throttle them.","Monitor l.failedCounter metrics to see how often the limit trips."],"exampleFix":"// before\nstoregw: seriesLimit: 100000\n// after\nstoregw: seriesLimit: 500000  # or narrow the query's matchers","handlingStrategy":"validation","validationCode":"// estimate series count before query via /api/v1/series or len(postings hint)\nif estimatedSeries*concurrentQueries > limit { /* reduce scope or raise limit */ }","typeGuard":null,"tryCatchPattern":"if err != nil {\n  var limErr interface{ Limit() uint64 }\n  // handle as \"limit exceeded\": back off or reduce query scope\n}","preventionTips":["Size limits from real cardinality data, not guesses","Alert on l.failedCounter metric spikes","Document the limits in runbooks for query authors"],"tags":["go","limits","resource-exhaustion"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}