Incident Library
  • Root cause
  • Component
  • Symptom
  • Contributing factor
  • Case

Cases18 cases

3 to 7 of 18

  1. Symptoms

    From 12:13 to 15:30 PDT on 25 March 2026, voice and video on Discord were heavily degraded. Users mostly could not start or join calls and saw "Awaiting Endpoint" in their call status.

    Trigger

    A routine change to tune the sessions service cluster on Kubernetes gave each pod more CPU and memory and lowered the pod count in proportion. When it was deployed to the first zone at 12:13 PDT, Kubernetes terminated 50% of that zone's pods, and the termination grace period ran out before the sessions could be handed off.

    Root cause
    Component
    Contributing factor
    Remediation
    • Set low syncer spawn rate limits in the calls, streams and guilds services and restarted the voice syncers cluster
    • Restarted voice syncers instances one at a time, and four of the first five recovered fully
    • Brought 15 new voice syncers instances online, doubling capacity and halving the syncers per instance
    • Restarted the last backed-up voice syncers instance, leaving the doubled cluster fully healthy
    Action items
    • Add a validating admission webhook that rejects a scale-down of Elixir workloads until each pod has handed off its processes
    • Replace the Holster.Pool supervisor with a PartitionSupervisor so outgoing connections are created and checked out concurrently
    • Move gun connection process lifecycle management into Holster.Pool so the gun connection supervisor is no longer used
    • Tune the upstream rate limits that call into voice syncers, with load shedding tooling that can force them
    • Add rate limits on endpoint selection in voice syncers to limit outbound connection creation
    • Monitor the HTTP connection pooling mailboxes
    • Review and expand instrumentation and logging for service discovery announcement and voice syncer RPCs to SFUs
    • Monitor the most critical processes across all services instead of aggregate metrics such as overall mailbox health
    • Bring more workloads into Kubernetes so capacity can be scaled with a single command instead of provisioning VMs by hand
    • Re-architect the A/V system to scale its control plane services horizontally across multiple regions
    Lessons

    Discord says a large enough traffic spike will find a bottleneck somewhere; in earlier large-load incidents its ScyllaDB databases limited recovery, and this time the bottleneck moved to the voice services. Facing a capacity constraint, the team asks whether to increase supply, such as adding services, or reduce demand, such as rate limiting inbound traffic. During an incident it matters to know the toolbox, and Elixir and the BEAM give engineers many introspection options. Any slowdown in the hot loop of a single-threaded process can degrade both the service and the user experience.

  2. Symptoms

    The day began with an alert that several instances of the Redis cluster were running out of disk space. That part was fixed quickly. The outage came an hour later: right after the Redis StatefulSet was deleted and recreated at 8:10 UTC, Kubernetes restarted every Redis pod within about five minutes, and problems started to appear.

    Trigger

    To make Git match the volumes that had been resized by hand, the Redis StatefulSet was deleted with orphan (non-cascading) deletion and recreated with the new storage template; Kubernetes reconciled the new spec by restarting the entire Redis cluster.

    Root cause
    Component
    Contributing factor
    Detection

    An alert about Redis instances running out of disk space started the work; the outage itself showed up as backend errors about Redis connections right after the StatefulSet was recreated.

    Remediation
    • made the Redis masters forget obsolete node identities, reset the affected replicas and rejoined them, then waited for replication to catch up
    • identified the component that was actually running out of memory, scaled the backend service and raised memory limits for that component
    • temporarily relaxed probes so backend instances took traffic immediately instead of flapping between ready and not ready
    • reverted the temporary workarounds at 10:00 UTC
    Action items
    • Add startup probes so a Redis pod is not marked ready until its dataset is loaded
    • Build an own control plane for Redis that handles restarted pods stuck to an old master address
    • Reduce dependence on the single Redis cluster: move some important data to other stores, such as a separate Redis cluster per server, and use Kafka for some backend components
    Lessons

    The disk resize was not the problem; the cleanup afterwards was. An immutable field pushes operators toward deleting and recreating the controller, and that can set off a full reconcile. Startup and readiness probes are what slow a rolling restart down to a safe pace; without them a distributed store restarts in the most fragile way. Recovery plans must expect a cluster to heal slowly, and dependent services need to degrade gracefully while it does.

  3. Symptoms

    On 21 October 2025 at 21:45 UTC a change to timeout handling was deployed to the feature flags service, and two minutes later automated monitoring reported higher error rates. The change was rolled back by 21:49, but error rates stayed high: about 38% of flag evaluation requests in the US datacenter returned errors. At 22:30 Redis metrics showed memory exhaustion on ElastiCache, at 22:35 Postgres connections spiked, and at 22:45 the team found a massive data transfer from Postgres into Redis. The main PostHog application was affected as well, because it shares the Redis instance with the flags service.

    Trigger

    On 21 October a deployment meant to reduce timeout errors (PR #39821); on 24 October the deployment of IP-based rate limiting (PR #40074) that saw all traffic as coming from the load balancer's IP; on 28 October an unrelated routine deployment that rolled the feature flag pods in the US region.

    Root cause
    Component
    Contributing factor
    Detection

    On 21 October automated monitoring detected higher error rates two minutes after the deploy. On 24 October no alert existed for 429 errors, and the team learned of the incident from customer reports that began at 18:10 UTC, a 62-minute detection delay. On 28 October on-call received a high error count alert. On 29 October the incident was reported with higher error rates and latency. No alert existed for CPU pressure, so the CPU saturation behind all three incidents was not seen directly.

    Remediation
    • rolled back the timeout handling change within 2 minutes on 21 October, which did not stop the errors
    • throttled connections and Redis writes on 21 October
    • halted the rollout on 28 October, scaled the US flags pods to zero until Redis recovered, then scaled them back gradually
    • rolled back hardware changes on 30 October at 00:03 UTC, which removed most errors but not the latency
    • increased the pod resource requests and adjusted the Kubernetes fleet size so fewer pods ran on each node
    • added retry limits to Envoy between the load balancer and the service
    • moved database connection timeouts and other critical settings to runtime configuration and raised the timeout values
    • added per-node and per-pod CPU alerts at 80% sustained for 5 minutes that page on-call
    Action items
    • Form a strike team from the flags, ingestion and infrastructure teams to review the application and infrastructure for remaining bottlenecks
    • Investigate separating the flags Redis instance from the application Redis instance
    • Before re-enabling ArgoCD sync, align the flags service chart configuration with the values in ArgoCD and define the deployment and Redis strategy
    • Make the feature flags team hard code-owners for flags-related code
    • Build a dashboard of key flag metrics with runbook links and update the feature flag runbooks
    • Add missing alerts on existing service and infrastructure metrics
    • Make readiness checks validate dependencies that degrade under load, for example by pinging the database
    • Rate-limit cache population so it cannot overwhelm Redis
    • Monitor connection pools with automatic throttling near exhaustion and limit concurrent connections
    • Build a production-scale load testing framework
    • Build progressive rollout infrastructure to limit blast radius
    • Document Postgres-to-Redis data flows and write runbooks for data transfer storms
    Lessons

    Nodes that are small relative to pod requests let the scheduler pack many pods on each node, and the resulting CPU saturation showed up three different ways: excessive parallelism, connection pool exhaustion and slow queries. Treating each symptom separately let the problem return; right-sizing the pods and nodes fixed all three. CPU must be alerted on from the start. Unbounded Envoy retries and unbounded cache population amplified the overload, and a Redis instance shared with the main application spread a flags problem to the main application. A rollback did not end the incident, because the data transfer and resource exhaustion it had started kept running.

  4. Symptoms

    At 11:48 PM PDT on 19 October 2025, every system that reached DynamoDB in us-east-1 through the public regional endpoint started getting DNS failures and could not connect. This included customer traffic and internal AWS services that depend on DynamoDB. DynamoDB global table replicas in other regions still answered but fell behind in replication to and from us-east-1.

    Trigger

    One DNS Enactor, slowed by unusually high retry delays, applied a much older DNS plan to the regional DynamoDB endpoint just as another Enactor that had applied the newest plan ran its clean-up, which deleted that older plan and with it every IP address of the endpoint.

    Root cause
    Component
    Contributing factor
    Detection

    DNS failures to DynamoDB began immediately at 11:48 PM PDT and the engineering teams of affected AWS services were engaged at once; by 12:38 AM they had identified DynamoDB's DNS state as the source. The later NLB health check problem was detected by monitoring at 6:52 AM.

    Remediation
    • applied temporary mitigations by 1:15 AM that let some internal services reach DynamoDB and repaired key internal tooling
    • restored all DynamoDB DNS information by 2:25 AM through manual operator intervention
    • throttled incoming work and selectively restarted DWFM hosts from 4:14 AM so droplet leases could be re-established
    • reduced the load on Network Manager to bring network configuration propagation times back to normal by 10:36 AM
    • disabled automatic health check failover for NLB at 9:36 AM, and re-enabled it at 2:09 PM after EC2 recovered
    • relaxed the EC2 request throttles from 11:23 AM until all EC2 APIs and launches were normal at 1:50 PM
    Action items
    • Disable the DynamoDB DNS Planner and DNS Enactor automation worldwide
    • Fix the race condition and add protections against applying incorrect DNS plans before re-enabling the DNS automation
    • Add a velocity control to NLB that limits how much capacity a single load balancer can remove when health check failures cause availability zone failover
    • Build an additional EC2 test suite that exercises the DWFM recovery workflow at scale
    • Improve throttling in EC2 data propagation systems so incoming work is rate limited by the size of the waiting queue
    Lessons

    A single DNS record that automation can empty is enough to take a widely used regional endpoint off the network, and every service built on it fails in turn. A check made once at the start of a long operation can be stale by the time the operation writes its result. Recovery of the dependency is not recovery of the dependents: systems that lost state during the outage, such as EC2's droplet leases and network propagation backlog, can collapse under their own catch-up work, and container services that rely on new instance launches keep failing to launch and scale until that work is done.

  5. Symptoms

    On 16 May 2025, in Neon's Kubernetes cluster in AWS us-east-1, new compute pods were scheduled but could not start and failed with IP allocation errors. Each Neon compute is a Postgres database running in a lightweight virtual machine in its own pod, so without new pods, idle customer databases could not be woken up.

    Trigger

    On 16 May the Neon control plane's periodic job that terminates idle computes started failing. Compute creations continued, and the number of active computes rose from about 5k to about 8.1k within minutes. On 19 May, a follow-up change that set WARM_IP_TARGET back to 1 started the second round of failures.

    Root cause
    Component
    Contributing factor
    Detection

    As cluster-autoscaler added nodes, the team saw IP allocation errors on new pods that were scheduled but could not start. The rate of successful pod starts and VPC subnet metrics were then used to follow the problem.

    Remediation
    • Set WARM_IP_TARGET=1 to release IPs held by nodes without free CPU or memory
    • Fixed the control plane's periodic job so idle computes were terminated again
    • Restarted the aws-node DaemonSet several times, each with a temporary improvement
    • Set WARM_IP_TARGET=0, MINIMUM_IP_TARGET=0 and WARM_ENI_TARGET=0, which let nodes allocate enough IPs and stabilised the cluster
    • On 19 May, set WARM_IP_TARGET back to 0 after setting it to 1 failed again
    • Enlarged the pool of pre-created warm compute pods to absorb failed pod starts
    Action items
    • Open a pull request to AWS CNI to improve how ipamd releases IPs in this situation
    • Follow up with AWS Support about the roughly 100 subnet IPs that were never allocated, for reasons Neon could not explain
    • Change the architecture to support horizontal scaling
    Lessons

    With default settings AWS CNI can keep many IPs on nodes that cannot use them, so the share of subnet IPs assigned to pods does not tell how close the subnet is to running out. WARM_IP_TARGET and WARM_ENI_TARGET follow different logic, a warm IP target of zero switches to the ENI logic, and IPs in cooldown count toward the target, which behaves badly under high pod churn. Changing these settings during an incident without knowing that logic prolonged the outage, and reverting a setting did not bring back the earlier healthy state.

Check your cluster for this

These 18 cases involve Container memory limit and In-memory cache. kubegap audits a Kubernetes cluster for gaps like these, read-only, from Claude Code or Codex; its checks cite public reports like the ones in this library.

By root cause4

Capacity exhaustion10 cases

  1. IL-0102 CoreDNS pods on a production EKS cluster ran out of memory under a burst of new pods, endpoints and nodes, taking down the Buildkite web UI, APIs and job dispatch
  2. IL-0100 PostHog's feature flags pods were packed onto Kubernetes nodes that were too small for their CPU requests, and CPU saturation above 90% caused three outages in ten days through Redis overload, connection pool exhaustion and slow queries
  3. IL-0006 VPC subnets ran out of IP addresses because the AWS VPC CNI kept IPs on full nodes, and WARM_IP_TARGET changes then blocked pod starts after every pod deletion
    Neon2025
  4. IL-0085 A control plane node of Magic Pages' Kubernetes cluster on Hetzner Cloud ran out of memory, the cluster's own calls then used up the Hetzner API rate limit, and all customer websites were down for about 7.5 hours
  5. IL-0168 Simultaneous cluster auto-upgrades overloaded Scaleway's Kubernetes API, and a node authentication retry loop kept Kapsule and Kosmos nodes NotReady in FR-PAR
  6. IL-0169 The Scaleway Kubernetes API in FR-PAR ran out of memory under simultaneous deployments, and because it also handled node authentication, Kapsule and Kosmos nodes went NotReady
  7. IL-0202 A burst of queries and database writes exhausted connection pools and memory on Honeycomb's ingest hosts, and Kubernetes crash-loop back-off kept failed hosts offline so ingest capacity stayed too low to recover
  8. IL-0140 The GKE API in us-central1 returned errors and high latency for 3 hours 19 minutes after an unexpected rise in backend traffic that client retries made worse
  9. IL-0076 Kubernetes masters went down after Dex filled etcd with AuthRequest objects and deleting its namespace started an endless list-and-timeout loop
  10. IL-0001 Cluster-wide DNS outage after CoreDNS pods were OOM-killed again and again under a burst of DNS queries

Configuration change6 cases

  1. IL-0246 New pods on Adyen's big data Kubernetes nodes could not start, failing with "Cilium API client timeout exceeded"
    Adyen2026
  2. IL-0499 Discord voice and video calls hung at Awaiting Endpoint for three hours after 17% of sessions stopped at once
  3. IL-0063 VPN outage after recreating a Redis StatefulSet restarted the whole Redis cluster without readiness checks
  4. IL-0177 WebSocket connections to LINE's messaging-hub on Kubernetes dropped all at once whenever another service's change reloaded a shared HAProxy L7 load balancer, and the reconnect wave overloaded a token API and filled nf_conntrack on Nginx
  5. IL-0461 Every rollout of Datadog's metrics query service on Kubernetes raised errors that the logs blamed on DNS
  6. IL-0004 A new default pod priority let a new Cortex cluster preempt every production ingester in a cascade, taking Grafana Cloud Hosted Prometheus down

Software defect1 case

  1. IL-0150 A latent race condition in DynamoDB's DNS automation left an empty DNS record for dynamodb.us-east-1.amazonaws.com, and the DynamoDB and EC2 launch failures that followed caused EKS, ECS and Fargate container launch failures and cluster scaling delays in us-east-1

Cloud provider outage1 case

Organisation
  1. IL-0542 Twingate authentication and authorization requests failed at higher rates after traffic moved onto a smaller GKE cluster