thanos-io/thanos · warning
too many timeseries
Error message
too many timeseries
What it means
HTTP 413 returned by the OTLP handler when the number of time series in one request exceeds the tenant's per-request series limit enforced by requestLimiter.AllowSeries. This is a per-request cap, distinct from the total active-series limit, designed to bound memory needed to process a single write.
Solutions
- Reduce exporter batch size so each request carries fewer series.
- Increase the tenant's max series per request in the request limiter config.
- Split exports across multiple requests at the collector (e.g. batch/queued-retry processors with smaller batches).
- Aggregate/drop unneeded metrics in an OTTL processor before exporting.
Example fix
# before: one huge batch batch: send_batch_size: 100000 # after batch: send_batch_size: 5000 send_batch_max_size: 5000
Defensive patterns
Strategy: validation
Validate before calling
if seriesCount > maxSeriesPerRequest { splitIntoBatches(metrics, maxSeriesPerRequest) } Try / catch
if resp.StatusCode == 413 { reduceBatchSize(); retry() } Prevention
- Tune collector batch processor send_batch_max_size
- Know your metric count per target and size limits above it
- Alert on 413 responses from receive
When it happens
Trigger: A single OTLP export whose converted metric count exceeds the tenant's max series per request (request.series_limit / max_series).
Common situations: Exporter batching too many resource-metrics into one payload; many targets scraped into one export; per-request limit configured below the application's natural metric count.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- write request too large
- too many samples
- Admin operations are disabled
- tenant is above active series limit
- error converting OTLP metrics to Prometheus format
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/b9c5ecfb3cab7a3f.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/receive/handler_otlp.go:88
if err != nil {
level.Error(h.logger).Log("msg", "Error decoding remote write request", "err", err.Error())
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
metrics, _, err := h.convertToPrometheusFormat(ctx, req.Metrics())
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
totalSamples := 0
for _, ts := range metrics {
totalSamples += len(ts.Samples)
}
if !requestLimiter.AllowSeries(tenant, int64(len(metrics))) {
http.Error(w, "too many timeseries", http.StatusRequestEntityTooLarge)
return
}
if !requestLimiter.AllowSamples(tenant, int64(totalSamples)) {
http.Error(w, "too many samples", http.StatusRequestEntityTooLarge)
return
}
rep := uint64(0)
// If the header is empty, we assume the request is not yet replicated.
if replicaRaw := r.Header.Get(h.options.ReplicaHeader); replicaRaw != "" {
if rep, err = strconv.ParseUint(replicaRaw, 10, 64); err != nil {
http.Error(w, "could not parse replica header", http.StatusBadRequest)
return
}
}
//TODO: (nicolastakashi) Handle metadata in the future.View on GitHub (pinned to 35b8b99117)