
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Mon, 06 Apr 2026 21:35:23 GMT</lastBuildDate>
        <item>
            <title><![CDATA[A deep dive into Cloudflare’s September 12, 2025 dashboard and API outage]]></title>
            <link>https://blog.cloudflare.com/deep-dive-into-cloudflares-sept-12-dashboard-and-api-outage/</link>
            <pubDate>Sat, 13 Sep 2025 07:19:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare’s Dashboard and a set of related APIs were unavailable or partially available for an hour starting on Sep 12, 17:57 UTC.  The outage did not affect the serving of cached files via the  ]]></description>
            <content:encoded><![CDATA[ <p></p>
    <div>
      <h2>What Happened</h2>
      <a href="#what-happened">
        
      </a>
    </div>
    <p>We had an outage in our Tenant Service API which led to a broad outage of many of our APIs and the Cloudflare Dashboard. </p><p>The incident’s impact stemmed from several issues, but the immediate trigger was a bug in the dashboard. This bug caused repeated, unnecessary calls to the Tenant Service API. The API calls were managed by a React useEffect hook, but we mistakenly included a problematic object in its dependency array. Because this object was recreated on every state or prop change, React treated it as “always new,” causing the useEffect to re-run each time. As a result, the API call executed many times during a single dashboard render instead of just once. This behavior coincided with a service update to the Tenant Service API, compounding instability and ultimately overwhelming the service, which then failed to recover.</p><p>When the Tenant Service became overloaded, it had an impact on other APIs and the dashboard because Tenant Service is part of our API request authorization logic.  Without Tenant Service, API request authorization can not be evaluated.  When authorization evaluation fails, API requests return 5xx status codes.</p><p>We’re very sorry about the disruption.  The rest of this blog goes into depth on what happened, and what steps we are taking to prevent it from happening again.  </p>
    <div>
      <h2>Timeline</h2>
      <a href="#timeline">
        
      </a>
    </div>
    <table><tr><th><p>Time (UTC)</p></th><th><p>Description</p></th></tr><tr><td><p>2025-09-12 16:32</p></td><td><p>A new version of the Cloudflare Dashboard is released which contains a bug that will trigger many more calls to the /organizations endpoint, including retries in the event of failure.</p></td></tr><tr><td><p>2025-09-12 17:50</p></td><td><p>A new version of the Tenant API Service is deployed.</p></td></tr><tr><td><p>2025-09-12 17:57</p></td><td><p>The Tenant API Service becomes overwhelmed as new versions are deploying. Dashboard Availability begins to drop <b>IMPACT START</b></p></td></tr><tr><td><p>2025-09-12 18:17</p></td><td><p>After providing more resources to the Tenant API Service, the Cloudflare API climbs to 98% availability, but the dashboard does not recover. <b>IMPACT DECREASE</b></p></td></tr><tr><td><p>2025-09-12 18:58</p></td><td><p>In an attempt to restore dashboard availability, some erroring codepaths were removed and a new version of the Tenant Service is released. This was ultimately a bad change and causes API Impact again. <b>IMPACT INCREASE</b></p></td></tr><tr><td><p>2025-09-12 19:01</p></td><td><p>In an effort to relieve traffic against the Tenant API Service, a temporary ratelimiting rule is published.</p></td></tr><tr><td><p>2025-09-12 19:12</p></td><td><p>The problematic changes to the Tenant API Service are reverted, and Dashboard Availability returns to 100%. <b>IMPACT END</b></p></td></tr></table>
    <div>
      <h3>Dashboard availability</h3>
      <a href="#dashboard-availability">
        
      </a>
    </div>
    <p>The Cloudflare dashboard was severely impacted throughout the full duration of the incident.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OI52n6YrKdSBxQIShw5al/3ecb621d4e6a56d43699d16e0e984055/BLOG-3011_1.png" />
          </figure>
    <div>
      <h3>API availability</h3>
      <a href="#api-availability">
        
      </a>
    </div>
    <p>The Cloudflare API was severely impacted for two periods during the incident when the Tenant API Service was down.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/19udRtEzYji4dSRwljaYxP/44f42a9cbc92cba22fdead28c177da21/BLOG-3011_2.png" />
          </figure>
    <div>
      <h2>How we responded</h2>
      <a href="#how-we-responded">
        
      </a>
    </div>
    <p>Our first goal in an incident is to restore service.  Often that involves fixing the underlying issue directly, but not always.  In this case we noticed increased usage across our Tenant Service, so we focused on reducing the load and increasing the available resources.  We installed a global rate limit on the Tenant Service to help regulate the load.  The Tenant Service is a GoLang process that runs on Kubernetes in a subset of our datacenters.  We increased the number of pods available as well to help improve throughput.  While we did this, we had others on the team continue to investigate why we were seeing the unusually high usage.  Ultimately, increasing the resources available to the tenant service helped with availability but was insufficient to restore normal service.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/UOY1fEUaSzxRE6tNrsBPu/fd02638a5d2e37e47f5c9a9888b5eac3/BLOG-3011_3.png" />
          </figure><p>After the Tenant Service began reporting healthy again and the API largely recovered, we still observed a considerable number of errors being reported from the service. We theorized that these were responsible for the ongoing Dashboard availability issues and made a patch to the service with the expectation that it would improve the API health and restore the dashboard to a healthy state. Ultimately this change degraded service further and was quickly reverted. The second outage can be seen in the graph above.</p><p>It’s painful to have an outage like this.  That said, there were a few things that helped lessen the impact.  Our automatic alerting service quickly identified the correct people to join the call and start working on remediation.  Additionally, this was a failure in the control plane which has strict separation of concerns from the data plane.  Thus, the outage did not affect services on Cloudflare’s network.  The majority of users at Cloudflare were unaffected unless they were making configuration changes or using our dashboard.</p>
    <div>
      <h2>Going forward</h2>
      <a href="#going-forward">
        
      </a>
    </div>
    <p>We believe it’s important to learn from our mistakes and this incident is an opportunity to make some improvements.  Those improvements can be categorized as either ways to reduce / eliminate the impact of a similar change or as improvements to our observability tooling to better inform the team during future events.</p>
    <div>
      <h3>Reducing impact</h3>
      <a href="#reducing-impact">
        
      </a>
    </div>
    <p>We use Argo Rollouts for releasing, which monitors deployments for errors and automatically rolls back that service on a detected error.  We’ve been migrating our services over to Argo Rollouts but have not yet updated the Tenant Service to use it.  Had it been in place, we would have automatically rolled back the second Tenant Service update limiting the second outage.  This work had already been scheduled by the team and we’ve increased the priority of the migration.</p><p>When we restarted the Tenant Service, everyone’s dashboard began to re-authenticate with the API.  This caused the API to become unstable again causing issues with everyone’s dashboard.  This pattern is a common one often referred to as a Thundering Herd.  Once a resource or service is made available, everyone tries to use it all at once. This is common, but was amplified by the bug in our dashboard logic. The fix for this behavior has already been released via a hotfix shortly after the impact was over.  We’ll be introducing changes to the dashboard that include random delays to spread out retries and reduce contention as well. </p><p>Finally, the Tenant Service was not allocated sufficient capacity to handle spikes in load like this. We’ve allocated substantially more resources to this service, and are improving the monitoring so that we will be proactively alerted before this service hits capacity limits.</p>
    <div>
      <h3>Improving visibility</h3>
      <a href="#improving-visibility">
        
      </a>
    </div>
    <p>We immediately saw an increase in our API usage but found it difficult to identify which requests were retries vs new requests.  Had we known that we were seeing a sustained large volume of new requests, it would have made it easier to identify the issue as a loop in the dashboard.  We are adding changes to how we call our APIs from our dashboard to include additional information, including if the request is a retry or new request.</p><p>We’re very sorry about the disruption.  We will continue to investigate this issue and make improvements to our systems and processes.</p> ]]></content:encoded>
            <category><![CDATA[Outage]]></category>
            <category><![CDATA[Post Mortem]]></category>
            <guid isPermaLink="false">7xKJsK5ZM4e3RrUVd8IVPQ</guid>
            <dc:creator>Tom Lianza</dc:creator>
            <dc:creator>Joaquin Madruga</dc:creator>
        </item>
        <item>
            <title><![CDATA[A Byzantine failure in the real world]]></title>
            <link>https://blog.cloudflare.com/a-byzantine-failure-in-the-real-world/</link>
            <pubDate>Fri, 27 Nov 2020 12:00:00 GMT</pubDate>
            <description><![CDATA[ At Cloudflare, we are always on the lookout for Single Points of Failure. In this post, we explore the role a failure mode known as a Byzantine fault played in a a real-world incident. ]]></description>
            <content:encoded><![CDATA[ <p><i>An analysis of the Cloudflare API availability incident on 2020-11-02</i></p><p>When we review design documents at Cloudflare, we are always on the lookout for Single Points of Failure (SPOFs). Eliminating these is a necessary step in architecting a system you can be confident in. Ironically, when you’re designing a system with built-in redundancy, you spend most of your time thinking about how well it functions when that redundancy is lost.</p><p>On November 2, 2020, Cloudflare had an <a href="https://www.cloudflarestatus.com/incidents/9ggr0k6dwzwg">incident</a> that impacted the availability of the API and dashboard for six hours and 33 minutes. During this incident, the success rate for queries to our API periodically dipped as low as 75%, and the dashboard experience was as much as 80 times slower than normal. While Cloudflare’s edge is massively distributed across the world (and kept working without a hitch), Cloudflare’s control plane (API &amp; dashboard) is made up of a large number of microservices that are redundant across two regions. For most services, the databases backing those microservices are only writable in one region at a time.</p><p>Each of Cloudflare’s control plane data centers has multiple racks of servers. Each of those racks has two switches that operate as a pair—both are normally active, but either can handle the load if the other fails. Cloudflare survives rack-level failures by spreading the most critical services across racks. Every piece of hardware has two or more power supplies with different power feeds. Every server that stores critical data uses RAID 10 redundant disks or storage systems that replicate data across at least three machines in different racks, or both. Redundancy at each layer is something we review and require. So—how could things go wrong?</p><p>In this post we present a timeline of what happened, and how a difficult failure mode known as a Byzantine fault played a role in a cascading series of events.</p>
    <div>
      <h3>2020-11-02 14:43 UTC: Partial Switch Failure</h3>
      <a href="#2020-11-02-14-43-utc-partial-switch-failure">
        
      </a>
    </div>
    <p>At 14:43, a network switch started misbehaving. Alerts began firing about the switch being unreachable to pings. The device was in a partially operating state: network control plane protocols such as <a href="https://en.wikipedia.org/wiki/Link_aggregation#Link_Aggregation_Control_Protocol">LACP</a> and <a href="https://www.cloudflare.com/learning/security/glossary/what-is-bgp/">BGP</a> remained operational, while others, such as vPC, were not. The vPC link is used to synchronize ports across multiple switches, so that they appear as one large, aggregated switch to servers connected to them. At the same time, the data plane (or forwarding plane) was not processing and forwarding all the packets received from connected devices.</p><p>This failure scenario is completely invisible to the connected nodes, as each server only sees an issue for some of its traffic due to the load-balancing nature of LACP. Had the switch failed fully, all traffic would have failed over to the peer switch, as the connected links would've simply gone down, and the ports would've dropped out of the forwarding LACP bundles.</p><p>Six minutes later, the switch recovered without human intervention. But this odd failure mode led to further problems that lasted long after the switch had returned to normal operation.</p>
    <div>
      <h3>2020-11-02 14:44 UTC: etcd Errors begin</h3>
      <a href="#2020-11-02-14-44-utc-etcd-errors-begin">
        
      </a>
    </div>
    <p>The rack with the misbehaving switch included one server in our etcd cluster. We use <a href="https://etcd.io/">etcd</a> heavily in our core data centers whenever we need strongly consistent data storage that’s reliable across multiple nodes.</p><p>In the event that the cluster leader fails, etcd uses the <a href="https://raft.github.io/">RAFT</a> protocol to maintain consistency and establish consensus to promote a new leader. In the RAFT protocol, cluster members are assumed to be either available or unavailable, and to provide accurate information or none at all. This works fine when a machine crashes, but is not always able to handle situations where different members of the cluster have conflicting information.</p><p>In this particular situation:</p><ul><li><p>Network traffic between node 1 (in the affected rack) and node 3 (the leader) was being sent through the switch in the degraded state,</p></li><li><p>Network traffic between node 1 and node 2 were going through its working peer, and</p></li><li><p>Network traffic between node 2 and node 3 was unaffected.</p></li></ul><p>This caused cluster members to have conflicting views of reality, known in distributed systems theory as a <a href="https://en.wikipedia.org/wiki/Byzantine_fault">Byzantine fault</a>. As a consequence of this conflicting information, node 1 repeatedly initiated leader elections, voting for itself, while node 2 repeatedly voted for node 3, which it could still connect to. This resulted in ties that did not promote a leader node 1 could reach. RAFT leader elections are disruptive, blocking all writes until they're resolved, so this made the cluster read-only until the faulty switch recovered and node 1 could once again reach node 3.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/37eeMzKeltqOt105GJ4ctK/0a0a320ace579b8f28cc2aded23abc9a/image1-20.png" />
            
            </figure>
    <div>
      <h3>2020-11-02 14:45 UTC: Database system promotes a new primary database</h3>
      <a href="#2020-11-02-14-45-utc-database-system-promotes-a-new-primary-database">
        
      </a>
    </div>
    <p>Cloudflare’s control plane services use relational databases hosted across multiple clusters within a data center. Each cluster is configured for <a href="https://www.cloudflare.com/learning/performance/glossary/application-availability/">high availability</a>. The cluster setup includes a primary database, a synchronous replica, and one or more asynchronous replicas. This setup allows redundancy within a data center. For cross-datacenter redundancy, a similar high availability secondary cluster is set up and replicated in a geographically dispersed data center for disaster recovery. The cluster management system leverages etcd for cluster member discovery and coordination.</p><p>When etcd became read-only, two clusters were unable to communicate that they had a healthy primary database. This triggered the automatic promotion of a synchronous database replica to become the new primary. This process happened automatically and without error or data loss.</p><p>There was a defect in our cluster management system that requires a rebuild of all database replicas when a new primary database is promoted. So, although the new primary database was available instantly, the replicas would take considerable time to become available, depending on the size of the database. For one of the clusters, service was restored quickly. Synchronous and asynchronous database replicas were rebuilt and started replicating successfully from primary, and the impact was minimal.</p><p>For the other cluster, however, performant operation of that database <i>required</i> a replica to be online. Because this database handles authentication for API calls and dashboard activities, it takes a lot of reads, and one replica was heavily utilized to spare the primary the load. When this failover happened and no replicas were available, the primary was overloaded, as it had to take all of the load. This is when the main impact started.</p>
    <div>
      <h3>Reduce Load, Leverage Redundancy</h3>
      <a href="#reduce-load-leverage-redundancy">
        
      </a>
    </div>
    <p>At this point we saw that our primary authentication database was overwhelmed and began shedding load from it. We dialed back the rate at which we push SSL certificates to the edge, send emails, and other features, to give it space to handle the additional load. Unfortunately, because of its size, we knew it would take several hours for a replica to be fully rebuilt.</p><p>A silver lining here is that every database cluster in our primary data center also has online replicas in our secondary data center. Those replicas are not part of the local failover process, and were online and available throughout the incident. The process of steering read-queries to those replicas was not yet automated, so we manually diverted API traffic that could leverage those read replicas to the secondary data center. This substantially improved our API availability.</p>
    <div>
      <h3>The Dashboard</h3>
      <a href="#the-dashboard">
        
      </a>
    </div>
    <p>The Cloudflare dashboard, like most web applications, has the notion of a user session. When user sessions are created (each time a user logs in) we perform some database operations and keep data in a Redis cluster for the duration of that user’s session. Unlike our API calls, our user sessions cannot currently be moved across the ocean without disruption. As we took actions to improve the availability of our API calls, we were unfortunately making the user experience on the dashboard worse.</p><p>This is an area of the system that is currently designed to be able to fail over across data centers in the event of a disaster, but has not yet been designed to work in both data centers at the same time. After a first period in which users on the dashboard became increasingly frustrated, we failed the authentication calls fully back to our primary data center, and kept working on our primary database to ensure we could provide the best service levels possible in that degraded state.</p>
    <div>
      <h3>2020-11-02 21:20 UTC Database Replica Rebuilt</h3>
      <a href="#2020-11-02-21-20-utc-database-replica-rebuilt">
        
      </a>
    </div>
    <p>The instant the first database replica rebuilt, it put itself back into service, and performance resumed to normal levels. We re-ramped all of the services that had been turned down, so all asynchronous processing could catch up, and after a period of monitoring marked the end of the incident.</p>
    <div>
      <h3>Redundant Points of Failure</h3>
      <a href="#redundant-points-of-failure">
        
      </a>
    </div>
    <p>The cascade of failures in this incident was interesting because each system, on its face, had redundancy. Moreover, no system fully failed—each entered a degraded state. That combination meant the chain of events that transpired was considerably harder to model and anticipate. It was frustrating yet reassuring that some of the possible failure modes were already being addressed.</p><p>A team was already working on fixing the limitation that requires a database replica rebuild upon promotion. Our user sessions system was inflexible in scenarios where we’d like to steer traffic around, and redesigning that was already in progress.</p><p>This incident also led us to revisit the configuration parameters we put in place for things that auto-remediate. In previous years, promoting a database replica to primary took far longer than we liked, so getting that process automated and able to trigger on a minute’s notice was a point of pride. At the same time, for at least one of our databases, the cure may be worse than the disease, and in fact we may not want to invoke the promotion process so quickly. Immediately after this incident we adjusted that configuration accordingly.</p><p>Byzantine Fault Tolerance (BFT) is a hot research topic. Solutions have been known since 1982, but have had to choose between a variety of engineering tradeoffs, including security, performance, and algorithmic simplicity. Most general-purpose cluster management systems choose to forgo BFT entirely and use protocols based on PAXOS, or simplifications of PAXOS such as RAFT, that perform better and are easier to understand than BFT consensus protocols. In many cases, a simple protocol that is known to be vulnerable to a rare failure mode is safer than a complex protocol that is difficult to implement correctly or debug.</p><p>The first uses of BFT consensus were in safety-critical systems such as aircraft and spacecraft controls. These systems typically have hard real time latency constraints that require tightly coupling consensus with application logic in ways that make these implementations unsuitable for general-purpose services like etcd. Contemporary research on BFT consensus is mostly focused on applications that cross trust boundaries, which need to protect against malicious cluster members as well as malfunctioning cluster members. These designs are more suitable for implementing general-purpose services such as etcd, and we look forward to collaborating with researchers and the open source community to make them suitable for production cluster management.</p><p>We are very sorry for the difficulty the outage caused, and are continuing to improve as our systems grow. We’ve since fixed the bug in our cluster management system, and are continuing to tune each of the systems involved in this incident to be more resilient to failures of their dependencies.  If you’re interested in helping solve these problems at scale, please visit <a href="https://www.cloudflare.com/careers/">cloudflare.com/careers</a>.</p>
    <div>
      <h3>Postscript</h3>
      <a href="#postscript">
        
      </a>
    </div>
    <p>The distributed systems community has pointed out that the failure we've encountered would be better characterized as an omission fault rather than a Byzantine fault. Omission faults are much more specific and can be tolerated without BFT protocols.</p><p>We’re grateful to all those who read and critiqued this post and will be following up with a detailed post about different fault types in distributed systems soon. Stay tuned.</p> ]]></content:encoded>
            <category><![CDATA[Post Mortem]]></category>
            <category><![CDATA[API]]></category>
            <category><![CDATA[Postgres]]></category>
            <category><![CDATA[Outage]]></category>
            <guid isPermaLink="false">7cztH7o1B3T3GmwGGNBZ6v</guid>
            <dc:creator>Tom Lianza</dc:creator>
            <dc:creator>Chris Snook</dc:creator>
        </item>
    </channel>
</rss>