IL-0378 Cloudflare · 2025-03-21database
All Cloudflare R2 object writes and about 35% of reads failed when the R2 Gateway could not authenticate to storage
R2 is made of three parts: the production gateway Worker that serves the S3 API, REST API and Workers API, a metadata service, and storage infrastructure that holds the encrypted object data. The R2 Gateway Worker authenticates to the storage infrastructure with a credential ID and key pair that Cloudflare rotates regularly. Production and development are separate Workers environments, each an isolated Worker with its own environment variables and secrets, and both the wrangler secret put and wrangler deploy commands use the default environment when the --env parameter is left out.
On 21 March 2025 the R2 engineering team began a rotation at 19:49 UTC by creating new credentials while keeping the old ones. At 20:19 UTC the team set the new secret and deployed the gateway, but both commands were run without --env production, so the new credentials reached the Worker of the default environment while the production Worker kept the old ones. Believing production had been updated, the team removed the old credentials from the storage infrastructure at 20:37 UTC. As that deletion propagated, the production R2 Gateway Worker could no longer authenticate with the storage backend, and from 21:38 UTC writes failed and many reads failed; an intermediate cache in front of storage kept serving a large share of reads.
After alerts at 21:45 UTC and an internal incident declared at 21:50 UTC, the team suspected a credential propagation regression and twice made new credentials, the second set deployed again to the wrong Worker. At 22:36 UTC a review of the production Worker's release history showed that the credentials had gone to a non-production Worker. The team deployed them to the production Worker and R2 availability recovered at 22:45 UTC. No data was lost or corrupted: uploads and changes that had returned a successful HTTP status were stored. Cloudflare said the incident came from human error and lasted longer because it could not see which credentials the gateway Worker was using.
- Severity
- –
- Scope
- R2 object writes (100% failed) and object reads (about 35% failed globally), and services that use R2: Billing invoices, Cache Reserve, Email Security metrics, Images, Key Transparency Auditor, Log Delivery, Stream and Vectorize
- Users affected
- All customers using Cloudflare R2
- Region
- Global
- Time to detect
- 7m
- Time to resolve
- 1h 7m
Symptoms
From 21:38 UTC on 21 March 2025, Cloudflare R2 object storage returned errors for 1 hour and 7 minutes: all object writes failed and about 35% of object reads failed globally. R2 global availability alerts fired at 21:45 UTC, at a 2% error budget burn rate.
Operations that touch only metadata, such as head and list, kept working, and cached object reads were not affected, so customers reading public assets through custom domains saw fewer errors. Services built on R2 failed with it: all Images and Stream uploads failed, successful delivery of stored images fell to about 25%, Stream video segment delivery fell to 94% and Stream Live was down, all Key Transparency Auditor operations failed, all Vectorize insert and upsert operations failed, Logpush and Logpull log delivery was delayed by up to 70 minutes, Cache Reserve sent more requests to customer origins, customers could get errors when downloading past invoices, and Email Security metrics stopped updating.
The drop in availability was gradual and not obvious at first, because the deletion of the old credentials reached the storage infrastructure with a delay. Seeing a slow but steady decline in both read and write availability, the R2 engineering team suspected a regression in how new credentials propagate through the storage infrastructure. At 22:15 UTC the team created another set of credentials to force propagation again, with no improvement, and at 22:30 UTC it deployed a fresh set to the R2 Gateway Worker to check whether the credentials themselves were at fault; that deploy also lacked the environment parameter and went to the same non-production Worker.
Root cause
Root cause Operator error
- Trigger
- During a routine rotation of the credentials the R2 Gateway Worker uses to authenticate with the storage infrastructure, the new credentials were deployed to the Worker of the default environment instead of the production Worker, and the old credentials were then removed from the storage infrastructure at 20:37 UTC.
Detection
R2 global availability alerts fired at 21:45 UTC, seven minutes after impact began, at a 2% error budget burn rate, and the R2 engineering team turned to operational dashboards and logs.
Remediation
- Deployed the new credentials to the production R2 Gateway Worker, which restored R2 availability
Action items
- Add logging tags with the suffix of the credential ID the R2 Gateway Worker uses
- Require confirmation that the new token ID suffix matches storage infrastructure logs before deleting the old token
- Run key rotation through the hotfix release tooling, which enforces the environment, instead of manual wrangler commands
- Write the two-person validation of these changes into the standard operating procedures
- Extend the closed loop health check system to test new keys, report their status through alerting and confirm global propagation before releasing the gateway Worker
- Add observability views of upstream success rates that bypass caching
Lessons
Because the deletion of the old credentials took effect gradually, availability metrics were a poor way to confirm the change. Cloudflare said the team should have checked directly which token the R2 Gateway service was using to authenticate with the storage infrastructure instead of relying on those metrics.
Sources
Related cases
IL-0348Scaleway's FR-PAR region lost public internet connectivity when one 100 Gbps backbone link was saturatedScaleway · 2025same root cause · shared Object storage
IL-0534Amazon S3 in US-EAST-1 could not serve GET, LIST, PUT or DELETE requests for hours while its index subsystem restartedAmazon Web Services · 2017same root cause · shared Object storage
Check your cluster for this
For AI tools and scripts
- This case as JSON: https://incidentlib-api.benchlet.com/cases/IL-0378
- The cases most like it: https://incidentlib-api.benchlet.com/cases/IL-0378/similar
- MCP server (Streamable HTTP, no key):
https://incidentlib-mcp.benchlet.com/mcp
The API needs no key. The MCP server offers search_incidents, get_incident, list_incidents, get_topic and vocab; both are explained on API and MCP.