Documentation navigation
Mimir Discarding Samples (Series Limit)
Runbook for Mimir actively discarding metric samples due to the global series cap, triggered by the Mimir Discarding Samples (Series Limit) alert.
This is the data-loss companion to 04-mimir-ingester-series-limit.md. That runbook is the capacity pre-warning (80% of max_series); this one fires when the cap is hit and new series are being rejected.
Scope: The alert only fires on
reason=per_user_series_limit— the global series cap (limits.max_global_series_per_user). Other discard reasons (sample-out-of-order,new-value-for-timestamp,sample-timestamp-too-old) are caused by producer clock skew or WAL replay and are not alerted — they are a producer-side issue, not a Mimir capacity problem. They are still visible in thecortex_discarded_samples_totalmetric if you want to investigate them manually (see Notes).
Meaning
cortex_discarded_samples_total is a Mimir distributor/ingester counter that increments every time a sample is rejected. The metric only appears once a discard has happened — absence is healthy.
The reason label distinguishes the failure mode:
| reason | cause | alerted? | fix |
|---|---|---|---|
per_user_series_limit |
Global series cap (limits.max_global_series_per_user) hit — new series rejected at the distributor |
Yes | Raise the limit — see 04-mimir-ingester-series-limit.md |
sample-out-of-order |
A sample arrives with a timestamp older than the latest for the same series — producer clock skew or remote_write replay | No | Fix the producer clock or stop the replay |
new-value-for-timestamp |
A newer sample already exists for the same timestamp — duplicate/replay from a restarted collector | No | Identify and stop the duplicate source |
sample-timestamp-too-old |
Sample is older than reject_old_samples_max_age (720h on prd-par01) — very stale data from a misconfigured producer |
No | Fix the producer timestamp or raise the max age if historical backfill is intentional |
Why only per_user_series_limit is alerted
per_user_series_limit is the only reason that causes permanent, ongoing data loss — once the cap is hit, every new series is rejected until the limit is raised, and the affected dashboards/alerts go blind permanently. The timestamp/ordering reasons are intermittent — only the out-of-order/stale samples are dropped; subsequent in-order samples are ingested normally. They are caused by producer clock skew or WAL replay, not a Mimir capacity problem, so alerting on them would page oncall for a producer issue that Mimir config cannot fix.
Live context (2026-08-26)
- prd-par01: ~2070 samples/hr discarded with
reason=sample-out-of-order— a producer cluster is remote-writing samples with clock skew or replaying a backlog out of order. Not alerted. - dev-par01: ~284 samples/hr discarded with
reason=sample-out-of-order. Not alerted. - per_user_series_limit: not currently active on any cluster — the series-limit pre-warning (
04-mimir-ingester-series-limit.md) catches it at 80% before the cap is hit.
Impact
- Dashboards go blind for the rejected series — the data is lost, not delayed.
- Alerts scoped to the rejected series do not fire — if the discarded samples were the only signal for an alert, that alert is blind.
- The series itself is rejected, so ALL future samples for that series are discarded until the limit is raised — the blindness is permanent for that series until the cap is increased.
Diagnosis
The alert labels carry k8s_cluster_name (the synapse-server cluster where Mimir runs) and reason (always per_user_series_limit for this alert). From the alert, note the cluster.
1. Confirm the discard rate
export KUBECONFIG=~/.kube/<cluster>.yaml # e.g. prd-par01.yaml
Confirm via Mimir (port-forward synapse-server-mimir-gateway in monitoring-system, header X-Scope-OrgID: corti):
QUERY='sum by (k8s_cluster_name, reason) (rate(cortex_discarded_samples_total{reason="per_user_series_limit"}[5m]))'
curl -s -G -H "X-Scope-OrgID: corti" "http://localhost:9090/prometheus/api/v1/query" --data-urlencode "query=$QUERY" | jq -r '.data.result[]? | "\(.metric.k8s_cluster_name) \(.metric.reason): \(.value[1]) samples/s"'
A value > 0 confirms the alert.
2. Check the series count
QUERY='sum by (k8s_cluster_name) (cortex_ingester_memory_series)'
QUERY2='topk(10, count by (__name__) (cortex_ingester_memory_series))'
See 04-mimir-ingester-series-limit.md for the full diagnosis and mitigation.
Mitigation
Step 1 — Activate PIM
Activate the required Azure Privileged Identity Management roles before touching production (MultiTenantEuOnlyAccessPimRoles / DevOpsPimRoles / Platform Team (privileged)), as in 03-kafka/01-consumer-lag.md.
Step 2 — Raise the series limit
Raise limits.max_global_series_per_user in the Mimir runtimeConfig. See 04-mimir-ingester-series-limit.md Mitigation step 4. The runtimeConfig is hot-reloaded — no restart needed. Verify ingester headroom first (RAM ~2.2KB/series).
Step 3 — Verify the fix
QUERY='sum by (k8s_cluster_name, reason) (rate(cortex_discarded_samples_total{reason="per_user_series_limit"}[5m]))'
The rate should drop to 0 (or the metric may disappear) once the fix takes effect.
Verify
- The alert clears once
rate(cortex_discarded_samples_total{reason="per_user_series_limit"}[5m])returns to 0 (metric may disappear) sustained for thefor: 5mwindow. cortex_ingester_memory_seriesis below themax_global_series_per_usercap.- Dashboards for the rejected series repopulate with new samples.
Notes
- Metric only appears on failure —
cortex_discarded_samples_totalis absent when healthy. The alert fires when it appears withreason=per_user_series_limitand a positive rate. - Relationship to series-limit runbook —
04-mimir-ingester-series-limit.mdis the capacity pre-warning (80% ofmax_series). This runbook is the active data-loss alert (series cap hit). When this fires, the fix is the same — this runbook is the "it's already happening" signal. - Unalerted reasons —
sample-out-of-order,new-value-for-timestamp,sample-timestamp-too-oldare NOT alerted. They are caused by producer clock skew or WAL replay and are a producer-side issue. They are visible in thecortex_discarded_samples_totalmetric (filter byreason) if you want to investigate them manually. The steady-state out-of-order discards on prd-par01/dev-par01 are low-rate and by-design — Mimir rejects out-of-order samples from producers with clock skew. k8s_cluster_namenotcluster— Mimir self-monitoring metrics natively carryk8s_cluster_name; annotations use{{ $labels.k8s_cluster_name }}.