GitHub’s August 17 outage postmortem, published on August 20, 2026, does something day-of status updates never can: it names the mechanism. In GitHub’s words, the outage began when traffic reached a new peak and a critical infrastructure component in its Central US data center failed to scale with it. Then, as those services threw errors, a client-side retry loop increased traffic during recovery, and GitHub had to mitigate that behavior before it could safely restore traffic. The outage lasted 7 hours and 47 minutes.
That second sentence is the one worth reading twice. A capacity failure is a vendor problem. A retry loop that makes recovery harder is a client problem, and every team that runs CI bots, webhook consumers, agent fleets or orchestrator retry wrappers against GitHub is a client. GitHub’s first listed remediation uses the phrase “retry budgets” and “retry storms” directly, which means the vocabulary for fixing this is GitHub’s own, not something we are importing.
This post covers what the postmortem establishes and what it deliberately leaves generic, where its figures differ from our own day-of tracking, the scale of the remediation, Copilot as a separate failure domain, and then a retry-budget standard grounded in the AWS Architecture Blog, a second Amazon engineering write-up and Google’s SRE book, with an audit checklist you can run against your own harness this week.
- 01GitHub names a capacity failure plus a retry loop.The postmortem says a critical infrastructure component in its Central US data center failed to scale when traffic hit a new peak, and that errors there triggered a client-side retry loop that increased traffic during recovery. GitHub had to mitigate the loop before it could safely restore traffic.
- 02Retry budgets are GitHub’s words, not ours.The first remediation item reads: consistent retry limits, retry budgets, and variable timeouts across service-to-service interactions to prevent retry storms and cascading load. The standard in this post operationalizes exactly that language for clients.
- 03The retrospective runs 11 minutes longer than day-of tracking.Our August 17 post recorded 7 hours 36 minutes from a 13:40 UTC open. GitHub’s postmortem states 7 hours and 47 minutes, and its incident summary puts the start at 13:28 UTC. Both are presented here with sources; the difference is a measurement start point, not an error.
- 04The remediation is measured in millions of cores.GitHub says it has since added more than 3 million CPU cores, 120 petabytes of high-speed storage and significant network capacity, and that Azure now serves roughly 58% of platform load and half of all Git operations, up from 12% of platform load in May.
- 05Agent fleets are the next retrying client.GitHub does not identify the retrying clients, and nothing in the postmortem points at AI agents. Forward-looking, though, agent fleets, CI bots, webhook consumers and orchestrator retry wrappers are exactly the class of client that retries on 5xx. Full-jitter backoff, per-process budgets, circuit breakers and honouring Retry-After are the fix.
01 — The postmortemWhat GitHub actually said on August 20.
The post is titled “The August 17 outage, and the work ahead” and it opens without hedging: “On August 17, GitHub experienced an outage that lasted 7 hours and 47 minutes.” The same opening names every affected surface in one sentence: “It disrupted github.com, authentication, GitHub Actions, APIs, pull requests, issues, and Copilot, affecting developers and organizations around the world.” GitHub also frames the event as “our second significant incident in August, following an actions failure on August 6,” a detail we note as context only.
The root-cause paragraph is short and specific about the where, and deliberately generic about the what: “Our investigation found that the outage began when traffic reached a new peak, and a critical infrastructure component in our Central US data center failed to scale with it.” No component is named. The next two sentences are the heart of this post.
“Errors in those services triggered a client-side retry loop that increased traffic during recovery. We had to mitigate that behavior before we could safely restore traffic.”— GitHub, “The August 17 outage, and the work ahead,” August 20, 2026
Three things follow from that wording. First, the retry loop is described as a recovery problem, not the trigger: capacity failed first, retries made the way back harder. Second, GitHub says it had to mitigate the loop before it could safely restore traffic, which means the retry behavior was on the critical path to recovery, not a side effect. Third, GitHub does not say which client was retrying, and it keeps that abstraction throughout the post. We keep it too.
The tone is unusually direct for a company postmortem. “If you were trying to ship software that day, we let you down,” GitHub writes, and the closing line commits to earning trust “through the scaling and reliability of the platform.” Whether that lands depends on the remediation list in section 04, which is where the numbers are.
Root cause
A critical infrastructure component failed to scale when traffic reached a new peak. GitHub names the data center and the failure mode, not the component.
Recovery amplifier
Errors in the affected services triggered a client-side retry loop that increased traffic during recovery. GitHub had to mitigate that behavior before it could safely restore traffic.
Copilot as a separate domain
GitHub confirms that most services recovered earlier in the day while some Copilot services took longer, which is what our day-of tracking showed from the outside.
02 — MechanismHow a retry loop turns a partial failure into a pile-on.
The mechanism GitHub describes is the textbook cascading-failure shape. A backend starts returning errors because it cannot scale. Clients see the errors and retry. Each retry is a fresh request against a backend that is already at or over capacity, so the error rate rises, so more clients retry, and the load the backend must absorb to recover keeps climbing precisely because it has not recovered. Google’s SRE book calls this out directly: without randomization, “a small perturbation (e.g., a network blip) can cause retry ripples to schedule at the same time, which can then amplify themselves.”
GitHub’s own incident summary, which we read via its Community Discussions mirror of the status-page record, gives one concrete measure of how far that amplification went. The Copilot Token Service normally serves 7,000 to 9,000 requests per second. During the incident it saw 70,000 to 100,000 requests per second. Taking the ends of both ranges, that is between roughly 8 and 14 times normal, which is to say an order of magnitude of extra traffic arriving at a service that was already struggling. We use that figure because it is GitHub’s, it is about a named internal service rather than a named client, and it illustrates amplification without asserting who caused it.
Copilot Token Service baseline
The request rate GitHub’s incident summary describes as normal for the Copilot Token Service. Source: GitHub’s own incident-thread summary, read via the Community Discussions mirror of the status-page record.
Copilot Token Service under the retry loop
Roughly 8 to 14 times the normal range, computed from the two stated ranges. GitHub reports the service fully recovered by 21:02 UTC, 13 minutes before the incident formally closed at 21:15 UTC.
Web and API traffic
Roughly 20% of web and API traffic errored at peak, and roughly 50% of archive and raw-content downloads, both per GitHub’s status-page incident summary. These are the figures our day-of post also reported as vendor-stated.
That abstraction matters for the lesson. If the post had named a single client, the temptation would be to file this as that client’s bug. Because it did not, the useful reading is the general one: any client that retries a failing request without a budget is a potential amplifier, and the only defense a platform has against an unbudgeted client is to throttle it, which is what “mitigate that behavior” means in practice. For the client-side half of the story, our API error handling and resilience reference covers the retriable-versus-non-retriable distinction that every retry policy has to start from.
03 — The deltaDay-of tracking versus the retrospective.
On August 17 we published GitHub Came Back Before Copilot Did, built from the 36 updates on GitHub’s status-page incident record. That post recorded the incident opening at 13:40:03 UTC and resolving at 21:15:46 UTC, for 7 hours 36 minutes, and stated that no root cause had been published. The August 20 postmortem gives a different duration, 7 hours and 47 minutes, and GitHub’s incident summary puts the start at 13:28 UTC with the same 21:15 UTC close. We are presenting both rather than silently overwriting our own published figure, because the difference is itself the story of what a retrospective adds.
| Figure | Our Aug 17 post (live tracking) | GitHub postmortem (Aug 20) | GitHub incident summary (mirror) |
|---|---|---|---|
| Timing | |||
| Start (UTC) | 13:40:03 (status page “Investigating”) | Not stated as a timestamp | 13:28 |
| End (UTC) | 21:15:46 | Not stated as a timestamp | 21:15 |
| Duration | 7 h 36 m (computed from timestamps) | 7 h 47 m (stated) | 7 h 47 m (13:28 to 21:15) |
| Cause and mechanism | |||
| Root cause | None published at time of writing | Central US component failed to scale at a new traffic peak | Central US datacenter named |
| Retry behavior | Mitigation note on partially disabling auth token retries | Client-side retry loop increased traffic during recovery | Copilot Token Service 7–9k RPS normal, 70–100k RPS peak |
| Component recovery | |||
| Actions recovery | Mitigated at 16:59 UTC, stayed clear | Not stated as a timestamp | Degradation resolved ~18:03 UTC |
| Copilot recovery | Cleared only at incident resolution, 21:15 UTC | “Some Copilot services took longer” than most services | Token Service fully recovered by 21:02 UTC |
The two start times are 12 minutes apart and the two durations are 11 minutes apart. The most likely reading, and it is our inference rather than anything either source states, is that the two figures measure from different start points: the moment the status page was first marked as investigating versus the moment GitHub’s own telemetry says traffic crossed the new peak. We are not going further than that. Both sources that give an end timestamp agree on 21:15 UTC. One further delta sits in the table: our day-of post recorded Actions mitigated at 16:59 UTC and staying clear, while GitHub’s incident summary puts an Actions degradation resolving around 18:03 UTC. We present both with their sources, as with the duration.
The larger lesson is about what each kind of source is for. A live-tracked timeline tells you when the vendor knew and what it said; a retrospective tells you what actually happened and when it started. Both are legitimate, and an incident review on your side should keep both columns rather than backfilling the retrospective number over the day-of one. The agentic workflow incident-response playbook has a runbook template that keeps those columns separate by design.
04 — RemediationThree million cores, 120 petabytes, and roughly 58% of platform load on Azure.
The remediation section is where the postmortem stops being a narrative and becomes a capacity plan. One sentence carries the headline figures: “We have since added more than 3 million CPU cores, 120 petabytes of high-speed storage, and significant network capacity.” Those are two clauses of a single sentence, not separate initiatives, and GitHub gives no breakdown of where the cores went.
The second figure is the Azure migration, and it is stated as two metrics in one breath: “Today, Azure serves roughly 58% of GitHub’s platform load and half of all Git operations, up from 12% of platform load in May.” GitHub gives no date within May for the 12% baseline and no date for “today” beyond the August 20 publish date, so both ends should be read as approximate. Taken at face value, that is a move of roughly 46 percentage points of platform load across a May-to-August window. GitHub does not break that shift down by month and does not say the migration changed pace, so nothing in the pair of figures isolates anything that happened after August 17. The signal is the size of the move, not its timing.
Share of GitHub served from Azure · May vs August 2026
Source: GitHub, “The August 17 outage, and the work ahead,” Aug 20, 2026. Dates approximate as stated by GitHub.Then come the engineering changes, and the order matters. First: “we are applying consistent retry limits, retry budgets, and variable timeouts across service-to-service interactions to prevent retry storms and cascading load.” Second: “we are reviewing lower-priority CPU and memory alerts to identify components that could fail during sudden traffic spikes.” The post also describes architecture work toward “unlimited read operations,” rolling out gradually beginning with the largest monorepos, which is framed as ongoing rather than complete.
Note the scope of that first item. GitHub is applying retry budgets to its own service-to-service calls, which is the internal half of the problem. The external half, the clients that retry against GitHub, is the half only clients can fix, and it is the half the rest of this post is about.
05 — Failure domainsCopilot recovered on its own clock, and GitHub now says so.
Our day-of post argued, from the outside, that the AI assistant in a developer loop sits on a different dependency chain from git hosting and recovers on a different clock. The postmortem confirms it from the inside in one sentence: “Most GitHub services recovered earlier that day, but some Copilot services took longer.” GitHub’s incident summary adds the detail that the Copilot Token Service, the service whose request rate spiked by an order of magnitude, was fully recovered by 21:02 UTC, 13 minutes before the incident closed at 21:15 UTC, while the status-page record had shown the Central US data center recovering by 16:36 UTC. We are not re-telling the outage day here; the timeline, the 16:59 UTC mitigation list and the relapses are all in the August 17 post. What the two GitHub sources add together is that the service which took longest to recover was also the one whose request rate spiked by an order of magnitude. GitHub does not connect those two facts explicitly, and neither do we beyond noting them side by side.
06 — The standardA retry-budget standard, grounded in primary engineering references.
“Retry budget” has a precise meaning, and it predates this outage by a decade. Google’s SRE book describes two distinct budgets. In the cascading-failures chapter it is process-wide: “Consider having a server-wide retry budget. For example, only allow 60 retries per minute in a process, and if the retry budget is exceeded, don’t retry; just fail the request.” In the overload chapter it is a per-client ratio: “Each client keeps track of the ratio of requests that correspond to retries. A request will only be retried as long as this ratio is below 10%.” The payoff of the ratio budget is stated directly: “layering on the per-client retry budget (a 10% retry ratio) reduces the growth to just 1.1x in the general case.”
Backoff shape comes from the AWS Architecture Blog’s “Exponential Backoff and Jitter”, Marc Brooker’s 2015 post that is still the canonical reference for the technique. It compares three jitter formulas and finds that Full Jitter did the least total client work of the three, because in a simulation of 100 contending clients plain exponential backoff without jitter produced synchronized retry spikes, and jitter spread those out to an approximately constant rate with less total client work. The post does not prescribe a cap or a maximum attempt count; those come from the SRE references. A separate Amazon write-up, “Timeouts, retries, and backoff with jitter”, supplies the rule for where retries belong: in a five-deep stack of service calls with three retries at each layer, it says the load on the database at the bottom increases 243 times, “making it unlikely to ever recover,” which is why Amazon states that “for low-cost control-plane and data-plane operations, our best practice is to retry at a single point in the stack.” The table below combines those four references with what GitHub’s own postmortem and REST API documentation say.
| Mechanism | What GitHub says | What AWS / Google SRE add | Applies to |
|---|---|---|---|
| Shape and limits of a single client’s retries | |||
| Backoff shape | “Variable timeouts” across service-to-service interactions (postmortem, first remediation item) | Full Jitter: sleep = random_between(0, min(cap, base × 2^attempt)) (AWS); “Always use randomized exponential backoff” (SRE) | Every client, every layer |
| Per-request cap | “Consistent retry limits” (postmortem) | Up to three attempts per request, then let the failure bubble up to the caller (SRE, overload chapter) | Every call site |
| Process-wide budget | “Retry budgets” (postmortem) | Illustrative 60 retries per minute per process; past the budget, fail the request instead (SRE, cascading failures) | CI runners, workers, agent processes |
| Per-client ratio budget | “Retry budgets” (postmortem) | Retry only while retries are below 10% of requests; caps growth at roughly 1.1× in the general case (SRE, overload) | Long-running clients and fleets |
| Interaction with the platform and with other layers | |||
| Multi-layer amplification check | “Prevent retry storms and cascading load” (postmortem) | A request at the top layer can produce as many attempts as the product of the attempts at each layer; retry at one layer only (SRE, cascading failures); Amazon’s worked example is 243× the load at the bottom of a five-deep stack | Orchestrators that wrap sub-agents |
| Retry-After and rate-limit headers | Wait the retry-after seconds; if x-ratelimit-remaining is 0, wait for x-ratelimit-reset; otherwise wait at least a minute (REST API docs) | Server-supplied waits outrank any client schedule; they are the platform’s own throttling signal | Anything calling the GitHub API |
| Circuit breaker and load shedding | “Mitigate that behavior before we could safely restore traffic” is the platform-side breaker (postmortem) | Adaptive throttling: self-throttle once requests reach K × accepts, K = 2 preferred; shed by criticality tier (SRE, overload) | Fleet-level controllers |
The three jitter formulas are short enough to show in full, and they are the part teams most often get wrong by implementing plain exponential backoff and calling it done.
Full Jitter
The AWS post’s own algorithm, and the one that did the least total client work in its 100-client simulation. Spreads synchronized retries across the whole backoff window.
Equal Jitter
Keeps a guaranteed minimum wait of half the window and randomizes the other half. Useful when a floor on the wait is required, at the cost of more total client work than Full Jitter in the post’s simulation.
Decorrelated Jitter
Derives each wait from the previous one rather than from the attempt count. In the post’s 100-client simulation it needed slightly more total client work than Full Jitter but slightly less time; the post calls the choice between the two “less clear”.
None of this is new, and that is the point. The references are a 2015 blog post, a continuously maintained book and Amazon’s own write-up on timeouts, retries and backoff. GitHub’s postmortem is a reminder that a platform at record scale still had to add consistent retry limits and retry budgets to its own internal calls in August 2026, which makes it unlikely your harness has them either. Our API rate-limiting reference covers the server side of the same contract.
07 — Forward-lookingAgent fleets are the next retrying client.
To be precise about what follows: GitHub does not identify the clients behind the August 17 retry loop, and nothing in its post suggests AI coding agents were involved. This section is about what comes next, not what happened. The class of client that retries on a 5xx has grown. A year ago it was CI runners, webhook consumers and a handful of integrations. Today it also includes agent fleets that clone, push, open pull requests and poll Actions on their own schedule, orchestrators that wrap those agents in their own retry logic, and tool-calling loops that treat a failed API call as something to try again immediately.
That last layer is where multi-layer amplification lives. Google’s SRE book warns that when retries happen at multiple levels, “a single request at the highest layer may produce a number of attempts as large as the product of the number of attempts at each layer.” An orchestrator that retries a task three times, wrapping a sub-agent that retries its tool call three times, wrapping an HTTP client that retries three times, is multiplicative by construction. The fix is structural: retry at one layer, and make every other layer fail fast and report.
GitHub’s REST API documentation already tells clients how to behave when the platform pushes back. Authenticated requests get 5,000 per hour, unauthenticated 60 per hour, and a GitHub Actions GITHUB_TOKEN gets 1,000 per hour per repository; secondary limits cap concurrency at 100 requests and content-generating requests at 80 per minute. On a 403 or 429, the documented behavior is to wait the number of seconds in the retry-after header if present, to wait until the x-ratelimit-reset timestamp if x-ratelimit-remaining is zero, to wait at least one minute when neither applies, and to use exponential backoff for continued failures. The docs also warn that continuing to make requests while rate-limited can result in the integration being banned. Read the rate-limits page as a contract your fleet has already agreed to. GitHub’s companion best-practices page adds two more rules: wait at least one second between each request when making a large number of POST, PATCH, PUT or DELETE calls, and, when a request keeps failing against a secondary limit, back off exponentially and “throw an error after a specific number of retries” rather than retrying indefinitely.
Scheduled, bursty, many in parallel
Dozens of runners hitting the same endpoints at the same minute is the synchronized-retry case the AWS post simulates. Full Jitter on every retry, a hard cap of three attempts per request, and a per-process budget so a red build fails visibly instead of hammering the API.
Inbound events that you acknowledge
The risk is on the write path: a retried handler that re-runs a side effect. Idempotency keys on every write, acknowledge fast, process asynchronously, and never retry the upstream call from inside the handler. See our webhook reliability reference.
Long-running, autonomous, tool-calling
An agent loop that treats a 5xx as a reason to call again is an unbudgeted client by default. The per-client 10% retry ratio from the SRE overload chapter is the right primitive here: it scales with the agent’s own traffic, and it caps growth at roughly 1.1× rather than letting a partial outage become a pile-on.
Retries that wrap other retries
The multiplicative case. Decide which single layer owns retries, make the other layers fail fast, and put a circuit breaker at the orchestrator so that once a dependency is clearly down the whole fleet stops calling it rather than each agent deciding independently.
Looking forward, the asymmetry is the thing to plan for. A platform can add three million CPU cores; it cannot make an unbudgeted client behave. Agent fleets, CI bots, webhook consumers and orchestrator retry wrappers all retry without a person watching the counter, and every one of them needs the discipline GitHub is now applying to its own services. The teams that treat retry budgets as part of the harness, rather than as something the HTTP library probably handles, are the ones whose fleets will still be making progress during the next partial outage instead of being throttled out of it. If that harness work is on your roadmap, our AI transformation engagements start from exactly this kind of reliability audit.
08 — AuditSeven questions to run against your own harness.
Six of the seven questions below map to a row of the standard in section 06. The seventh, on idempotent writes, has no row there, because it guards the write path rather than the retry rate. Run them against CI bots, webhook consumers and orchestrator retry wrappers specifically, because those are the clients most likely to have inherited a default retry policy nobody has read. A “no” on any row is a retry-amplification risk, and the fix column names the reference the fix comes from.
| Question | What a failing harness looks like | The fix and where it comes from |
|---|---|---|
| 1. Does each process track a retry ratio, or only per-call backoff? | Every call site backs off correctly on its own; nothing notices what share of the process’s traffic is now retries. | Per-client ratio budget, retry only below 10% (SRE, overload chapter), plus a process-wide cap such as 60 retries per minute (SRE, cascading failures). |
| 2. Is there a hard cap on attempts per logical request? | A retry-until-success loop, or a cap that resets when the task is re-queued. | Up to three attempts, then bubble the failure up to the caller (SRE, overload chapter). |
| 3. Does the client honour Retry-After and x-ratelimit-reset? | Retries on a fixed schedule regardless of what the 403 or 429 response says. | Wait the retry-after seconds, or until x-ratelimit-reset when remaining is zero (GitHub REST API docs). |
| 4. Is backoff jittered, or fixed-interval? | Sleep 1 s, 2 s, 4 s, 8 s with no randomization, so every runner retries in the same second. | Full Jitter: random_between(0, min(cap, base × 2^attempt)) (AWS Architecture Blog). |
| 5. Do retries stack across layers? | The orchestrator retries a task whose sub-agent already retried the call whose HTTP client already retried. | Retry at one layer only; attempts multiply across layers (SRE, cascading failures). |
| 6. Is there a circuit breaker for a dependency that is clearly down? | Each agent decides independently; the fleet as a whole keeps calling a service that has been failing for ten minutes. | Adaptive throttling at K × accepts with K = 2, plus a fleet-level breaker (SRE, overload chapter). |
| 7. Are retried writes idempotent? | A retried request opens a second pull request, posts a duplicate comment, or re-triggers a workflow. | Idempotency keys on every write so a retry cannot double-execute a side effect (see our webhook reference). |
For the full surface, our 70-point agentic workflow resilience audit folds these seven into a broader review, and the webhook reliability and idempotency reference goes deep on question seven. If you would rather have the audit run for you, it is a standard part of our web development engagements for teams shipping agent-driven pipelines.
09 — ConclusionThe controllable half of a platform outage.
Capacity is the vendor’s problem. Retry budgets are yours.
GitHub’s August 20 postmortem settles the questions our day-of post could not. The outage began when a critical infrastructure component in the Central US data center failed to scale at a new traffic peak; a client-side retry loop then increased traffic during recovery and had to be mitigated before service could be safely restored; the whole event ran 7 hours and 47 minutes by GitHub’s count, 11 minutes longer than the 7 hours 36 minutes we tracked live from a later start point. The remediation is more than 3 million CPU cores, 120 petabytes of storage, an Azure migration that GitHub puts at roughly 58% of platform load and half of all Git operations, and, first on the list, consistent retry limits and retry budgets.
What GitHub does not say is as instructive as what it does. It names no component and no client, and a more detailed mechanism circulating in secondary coverage is not in GitHub’s own account, so it is not in ours. The generic framing is the useful one: any client without a retry budget is a potential amplifier, and platforms defend themselves against unbudgeted clients by throttling them.
The forward-looking point is that the population of retrying clients is changing. Agent fleets, CI bots, webhook consumers and orchestrator retry wrappers are exactly the class of client that retries on 5xx, usually with no person watching the retry counter. Full-jitter backoff, a per-request cap, a per-process or per-client budget, a single retry layer, a circuit breaker, honoured Retry-After headers and idempotent writes are a decade-old standard. GitHub is now applying it to its own services. The next partial outage will sort fleets that did the same from fleets that got throttled.