Cases2 cases
1 to 2 of 2
- Symptoms
On 2 September 2025 the matrix.org homeserver went down at 17:45 UTC and stayed down until 18:00 UTC the next day. Both machines of its PostgreSQL cluster were out of action: the original primary had lost its RAID array during a disk expansion, and the data directory of the new primary had been deleted by mistake.
- Trigger
During maintenance to add drives, an existing drive disappeared from the primary database server's RAID 10 array at 11:17 UTC, which led to a failover and a rebuild of that server. The outage itself began when the data directory of the new primary on db-01 was deleted while clearing a failed restore on db-02.
- Root cause
- Component
- Contributing factor
- Detection
Monitoring fired when the drive disappeared from db-02's RAID array at 11:17 UTC, and Mythic Beasts confirmed the issue. The team realised it had deleted db-01's data directory, and the backend team was then paged, an incident was opened and an emergency was declared.
- Remediation
- Created a fresh RAID 10 array on db-02
- Unblocked WAL archiving from the new primary on db-01 to S3
- Started restoring db-02 from the S3 backups with wal-g
- Shut down Synapse and the damaged primary database
- Remounted the data partition of db-01 read-only
- Copied the WALs missing from S3 from db-01 to db-02
- Updated wal-g and patched it to continue from the partial restore
- Configured a restore_command wrapper that fetched WALs from S3 and the local files, and replayed them in standby mode
- Promoted db-02 to primary and restarted Synapse
- Ran backups against the primary while no replica existed
- Rebuilt db-01 as a replica from a base backup of db-02
- Action items
- Run pg_repack to reclaim free space
- Take incremental backups more often, since they restore faster than WAL replay
- Reduce Synapse's storage requirements
- Consider changing the terminal background colour by the database's role, for example by watching for the standby.signal file
- Consider wrapper scripts around sensitive commands, such as an alias for rm, and automating operations such as starting a base backup from primary to secondary
- Shorten the recovery time, with infrastructure from service providers
- Upgrade wal-g on all servers and repeat disaster recovery testing with it
- Explore ZFS local snapshots at the next hardware refresh
- Make status.matrix.org the source of truth during incidents and keep social media updated
- Lessons
Most of the difficulty came from the size of the database: restoring 51TB and replaying WALs took far longer than hoped, and incremental backups restore much faster than WAL replay. Running a destructive command on the wrong server was the turning point, and Matrix.org looks for better tooling and processes rather than blaming the individual; working as a trio did not catch the mistake, and server names that suggest a role caused confusion because a primary and a secondary swap roles. The recovery lost no data, but the recovery time needs to be shorter, and the wal-g versions on the disaster recovery server and the production servers had drifted apart.
- Symptoms
Users of the matrix.org homeserver found rooms that simply stopped working: sending a new message or joining as a new member failed, and where an error was shown at all it was "No create event in auth events". The team first heard of it from a user's bug report and similar reports in public Matrix rooms and on social media.
- Trigger
A background cleanup job that removes state groups which were created but never used began working on the corrupted part of the state_groups_state table; the first errors appeared in the logs on 27 June 2025.
- Root cause
- Component
- Contributing factor
- –
- Detection
A bug report from a user, followed by similar reports in public Matrix rooms and on social media.
- Remediation
- Disabled the cleanup job that removes redundant state groups as a precaution
- Restored the 26 June database backup into a new Postgres instance on Amazon EC2
- Added a Postgres constraint that rejects deleting the state of a state group still in use
- Rebuilt the corrupted index on state_groups_state overnight
- Found the state wrongly removed by the cleanup job by comparing the restored backup with production, and re-inserted it
- Lessons
Index corruption of this kind can sit unnoticed for months or years, because index entries that point into empty table space are ignored; it shows only once Postgres reuses that space. pg_amcheck did not detect it, although its check confirmed that no index rows were missing and the index only had extra ones.
These 2 cases involve Database and Database backups and snapshots. 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 cause2
Operator error1 case
- Contributing factor
- Organisation
Data loss or corruption1 case
- Component
- Contributing factor
- –
- Organisation