Two clocks for one GitLab.com loss: 00:00 UTC and 23:30 UTC, at least 5,000 projects in the postmortem, 5,037 in the log
Published 2026-10-12
On GitLab.com’s one primary and one hot-standby secondary, the 10 February 2017 postmortem prints two ends for database rows lost on 31 January 2017: the introduction says 17:20 and 00:00 UTC on that date, and the data-loss section says 17:20–23:30 UTC. It says the exact loss is hard to estimate: at least 5,000 projects, 5,000 comments, and roughly 700 users. The incident log archived at 2017-02-02 03:47:19 UTC prints ±6 hours, 5,037 projects, ±4,979 comments, and 707 users that were hard to confirm from Kibana. Those figures are vendor claims, not a census of objects that stayed gone. The same postmortem says projects restored from remaining Git data came back only in basic form, without issues or merge requests.
- Population
- GitLab.com production PostgreSQL on 31 January 2017. One primary and one hot-standby secondary. Hostnames in the postmortem: db1.cluster.gitlab.com and db2.cluster.gitlab.com. The standby is only for failover. Not self-managed GitLab, not GitHost, and not GitLab Enterprise customers, which the postmortem says were unaffected.
- Documents
- Vendor postmortem published 10 February 2017. Incident log captured by the Internet Archive at 2017-02-02 03:47:19 UTC. The Register, 2 February 2017, 05:57 UTC, quoting that log and a PR line. The 1 February prose account The Register links was not opened.
- Outside the lost database rows
- The postmortem says code repositories and wikis were unavailable during the outage but were not affected by the data loss. The log’s note says the incident affected the database, including issues and merge requests, but not the git repositories and wikis.
- What a count is
- Project, comment, and user figures are vendor estimates. The log calls the project total rough and the user total hard to tell from Kibana. They are not a census of objects that stayed gone after the later basic restore.
Comparison
| Printed figure | Value (as printed) | Unit | Claim label | Source |
|---|---|---|---|---|
| Loss-window end, postmortem introduction (same sentence also names 17:20 UTC on 31 January) | 00:00 | UTC on 31 January 2017 | Vendor claim | GitLab postmortem |
| Loss-window end, postmortem data-loss section (same sentence also names 17:20 UTC) | 23:30 | UTC on 31 January 2017 | Vendor claim | GitLab postmortem |
| LVM snapshot of the production database, postmortem timeline | ±17:20 | UTC on 31 January 2017 | Vendor claim | GitLab postmortem |
| Removal on the primary, postmortem timeline | ±23:30 | UTC on 31 January 2017 | Vendor claim | GitLab postmortem |
| Removal terminated, incident-log timeline | 23:27 | UTC on 31 January 2017 | Vendor incident log | Incident log |
| Loss duration, incident-log impact list | ±6 | hours | Vendor incident log | Incident log |
| Loss duration, The Register quoting the impact list | about 6 | hours | News quotation of the incident log | The Register |
| Projects, postmortem introduction (best estimate) | roughly 5,000 | projects | Vendor claim | GitLab postmortem |
| Projects, postmortem data-loss section | at least 5000 | projects | Vendor claim. The section says the exact loss is hard to estimate. | GitLab postmortem |
| Projects, incident-log impact list (same sentence: 4613 regular, 74 forks, 350 imports) | 5037 | projects, labeled roughly | Vendor incident log. Git repositories were not lost. Rows whose user or group already existed could be recreated without issues. | Incident log |
| Projects, The Register quoting the impact list | 5,037 | projects | News quotation of the incident log | The Register |
| Comments, postmortem introduction (same best-estimate sentence as the projects) | 5,000 | comments | Vendor claim | GitLab postmortem |
| Comments, postmortem data-loss section | 5000 | comments | Vendor claim | GitLab postmortem |
| Comments, incident-log impact list | ±4979 (so ±5000) | comments | Vendor incident log | Incident log |
| Comments, The Register quoting the impact list | about 4,979 | comments | News quotation of the incident log | The Register |
| Users, postmortem introduction | 700 | new user accounts | Vendor claim | GitLab postmortem |
| Users, postmortem data-loss section | roughly 700 | users | Vendor claim | GitLab postmortem |
| Users, incident-log impact list | 707 | users | Vendor incident log. Potentially, hard to tell for certain from the Kibana logs. | Incident log |
| Users, The Register quoting the impact list | 707 | users | News quotation of the incident log | The Register |
| Users, The Register standfirst | ~707 | users | News wording. Compresses the log’s 707 users lost potentially. Not a separate count. | The Register |
| Share of the user base, The Register attributing a GitLab PR line | less than 1 | percent of user base | Vendor PR claim reported by The Register. No denominator in the opened postmortem or in the log’s impact list. | The Register |
| Data already removed when the process was stopped, postmortem timeline | around 300 | GB | Vendor claim | GitLab postmortem |
| Size named when the removal was terminated, incident-log timeline | around 310 | GB | Vendor incident log. Same sentence as the 4.5 GB left. Not subtracted on this page. | Incident log |
| Data left when the removal was terminated, incident-log timeline | about 4.5 | GB | Vendor incident log | Incident log |
| Staging-to-production copy, postmortem recovery narrative | around 18 | hours | Vendor claim. A duration, not a throughput. | GitLab postmortem |
| Downtime, postmortem 5 Whys, problem 1 | about 18 | hours | Vendor claim. Not the copy-duration sentence. | GitLab postmortem |
| Time to restore, postmortem 5 Whys, problem 2 | over 18 | hours | Vendor claim. Not the copy-duration sentence. | GitLab postmortem |
| Azure classic disk throttle, postmortem recovery narrative | around 60 | Mbps | Vendor claim. Stated throttle (the postmortem prints around 60Mbps). Not a measured byte rate, and not converted. | GitLab postmortem |
| Disk throughput cap, incident log line dated 2017/02/01 04:00 | 60 | Mb/s | Vendor incident log. Stated cap, spelled Mb/s. The same sentence names network I/O between us-east and us-east-2 with no rate. Not a measured throughput, and not converted. The postmortem instead says there was no network bottleneck. | Incident log |
| rsync progress, incident log line dated 2017/02/01 03:00 | approximately 50 | percent of files | Vendor incident log. Progress snapshot, not a rate. | Incident log |
| rsync progress, incident log line dated 2017/02/01 04:00 | approximately 56.4 | percent of files | Vendor incident log. Progress snapshot, not a rate. | Incident log |
| Transfer progress, incident log line dated 2017/02/01 08:07 | 42 | percent of data size | Vendor incident log. Different denominator from the file-count percents. Not a rate. | Incident log |
| Database restored without webhooks, postmortem recovery narrative | 17:00 | UTC on 1 February 2017 | Vendor claim | GitLab postmortem |
| Final restoration procedures finished, postmortem recovery narrative | around 18:00 | UTC clock time | Vendor claim. The sentence prints around 18:00 UTC and does not repeat a calendar date. It follows the 1 February 17:00 sentence in the same section. | GitLab postmortem |
| Data transfer complete, incident log | 2017/02/02 16:28 | clock time as printed | Vendor incident log. The opened archive URL is timestamped 2017-02-02 03:47:19 UTC. This page does not resolve that ordering. | Incident log |
| Initial pg_basebackup sync while staging was being set up, incident log | ±20 | hours | Vendor incident log. An estimate for that sync, not the production copy of around 18 hours. | Incident log |
| Sequence increment, postmortem recovery steps | 100,000 | sequence increment | Vendor claim. Listed among steps the process would involve. Not shown here as a confirmed applied value. | GitLab postmortem |
| ID increment, incident-log restore checklist | 10k | ID increment | Vendor incident log. Checkbox marked done. Printed as 10k and not expanded on this page. | Incident log |
| pg_dump binary used for the daily backup, postmortem | 9.2 | PostgreSQL version | Vendor claim. Run where no data directory made Omnibus default to 9.2. The S3 bucket was empty. | GitLab postmortem |
| Production database, postmortem | 9.6 | PostgreSQL version | Vendor claim. The postmortem says 9.x releases are major, so 9.2 against 9.6 made pg_dump error. | GitLab postmortem |
| Webhook cutoff, incident-log impact list | 17:20 | clock time as printed (Jan 31st 17:20); the impact bullet does not say UTC | Vendor incident log. Webhooks created before this time were restored; later ones were lost. No webhook count is printed. | Incident log |
| Webhook cutoff, The Register quoting the log | 5.20pm | clock time as printed, no timezone in that bullet | News quotation of the incident log. This page does not convert it to 17:20 UTC. | The Register |
Derived extract of sentences those three pages print. Not a copy of the postmortem, not a dump of the incident log, and not a measured throughput series. Canonical pages are the source column. Around 60 Mbps and 60 Mb/s are not converted. The three rows near 18 hours are three sentences, not one duration. Checks below the table are the only arithmetic, and they are not source cells.
Checks on the printed figures
- Arithmetic: the log’s project addends
- 4613 + 74 + 350 = 5037. That sum matches the total the incident log prints in the same sentence, and the 5,037 The Register quotes. The log still says roughly. The sum is arithmetic on this page, not a new measurement and not a source cell.
- Not subtracted: gigabytes
- The log says that at 23:27 UTC, of around 310 GB only about 4.5 GB was left. The postmortem says around 300 GB had already been removed at about 23:30 UTC. This page does not subtract 310 − 4.5 and does not equate the difference with 300 GB. Both figures are approximate vendor wording.
- Not subtracted: clocks
- This page does not subtract 23:30 minus 17:20, does not turn ±6 hours into a clock end, and does not treat 00:00 UTC on 31 January as midnight at the start of 1 February. The introduction prints 17:20 and 00:00 UTC on January 31. The data-loss section prints 17:20 UTC to 23:30 UTC. The log prints ±6 hours and a termination at 23:27 UTC. Those sentences are left side by side.
- Not converted: Mbps, Mb/s, and the 18-hour sentences
- Around 60 Mbps is the postmortem’s stated throttle on Azure classic network disks. 60 Mb/s is the log’s stated disk throughput cap, spelled that way. Neither is converted to MB/s or to a byte count, and neither is divided into the copy duration. The postmortem also says the copy took around 18 hours, that GitLab.com was down for about 18 hours, and that restoring took over 18 hours. Those stay three rows. Progress percents on the log lines dated 2017/02/01 03:00, 04:00, and 08:07 are snapshots. Those lines do not print a timezone. File-count percent and data-size percent use different denominators. They are not a throughput.
- Not expanded: 10k versus 100,000
- The log checks off an ID increment of 10k. The postmortem lists a sequence increment of 100,000 among steps the recovery process would involve. This page does not expand 10k to 10000 and does not decide which value was applied.
- Percent with no denominator
- The Register reports a GitLab PR line of less than 1% of the user base. The opened postmortem does not print that line or a user-base total. The log’s impact list does not either. 707 is not turned into a share of anything on this page.
- Archive timestamp and a later clock on the same capture
- The opened archive URL is timestamped 2017-02-02 03:47:19 UTC. The body of that capture prints 2017/02/02 16:28 as data transfer complete. The postmortem, published 10 February 2017, prints a restore of the database without webhooks at 17:00 UTC on 1 February and a copy of around 18 hours. This page does not choose which completion clock is the one that happened.
Method
The cells are copied from three public pages opened on 12 October 2026: GitLab’s postmortem published 10 February 2017, the public incident log in the Internet Archive capture 20170202034719, and The Register’s article published 2 February 2017 at 05:57 UTC. Each table row is one printed sentence. The Register’s hour, project, comment, and user rows are quotations of that log, so they are not a second count. The live Google document, the Slack transcripts and gist linked from the log, Kibana, and a 1 February prose account named by The Register were not opened. No sample was refit. Arithmetic in the checks is labeled as arithmetic and is not a cell.
Limits
The population is GitLab.com’s production database on 31 January 2017: one primary, db1.cluster.gitlab.com, and one secondary in hot standby, db2.cluster.gitlab.com, the standby used only for failover. The postmortem says GitLab Enterprise customers, GitHost customers, and self-managed GitLab CE users were not affected, and that Git repositories and wikis were unavailable during the outage but were not lost. The documents are the 10 February 2017 postmortem, the incident log as captured at 2017-02-02 03:47:19 UTC, and The Register the same morning. No data license and no sample size are stated. This is one service’s narrative, not a released dataset. Not measured: a census of projects, comments, issues, snippets, merge requests, webhooks, or users that remained absent after the basic project restore; any denominator for the “less than 1% of our user base” line; a measured copy throughput (around 60 Mbps and 60 Mb/s are a stated throttle and a stated cap); why pg_basebackup stayed in poll; which of the two postmortem window-ends was intended. As printed, 00:00 UTC on 31 January falls earlier that calendar date than 17:20 UTC. This page does not rewrite it as 1 February.
What the signal catches, and what it misses
The named disagreement is the loss account, not a second outage. The 10 February 2017 postmortem’s introduction says modifications to projects, comments, user accounts, issues, and snippets between 17:20 and 00:00 UTC on 31 January were lost, and that the best estimate was roughly 5,000 projects, 5,000 comments, and 700 new user accounts. The data-loss section of the same postmortem says projects, issues, snippets, and similar rows created between 17:20 UTC and 23:30 UTC were lost, and that the exact loss is hard to estimate: at least 5,000 projects, 5,000 comments, and roughly 700 users. The incident log’s impact list prints ±6 hours, 5,037 projects (4,613 regular, 74 forks, and 350 imports, labeled roughly), ±4,979 comments (so ±5,000), and 707 users potentially. The Register quotes those log figures the same day, including about 4,979 comments and 707 users that were hard to tell from the Kibana logs, and its standfirst compresses that to about six hours for ~707 users. “700 new user accounts,” “roughly 700 users,” and “707 users lost potentially” are three wordings. The Register also reports a PR line, less than 1% of the user base, and says PR described the loss as peripheral metadata written during a 6-hour window. The opened postmortem does not print that percent or the word peripheral. Its nouns are the database objects above.
The fault on the primary is removal of the PostgreSQL data directory on the production host, meant for the secondary. The postmortem times that at about 23:30 UTC and says the engineer stopped the process a second or two after noticing, by which point around 300 GB had already been removed. The log times the termination at 23:27 UTC and says of around 310 GB only about 4.5 GB was left. The signal that catches the mistake is the operator seeing the host. It misses every object already unlinked: neither document lists the relations inside those gigabytes, and neither equates the gigabytes with the project count. Earlier that night, strace on pg_basebackup showed a hang in poll and, the postmortem says, no other meaningful information that might have explained why. That trace does not name the later removal, and it does not say why the client waited. The postmortem says the hang was normal behaviour that was not clearly documented: pg_basebackup waits silently for the primary to send replication data. The trace still did not show that on its own.
The backup signals that should have shown an empty dump did not produce a restorable backup. The postmortem says the daily S3 bucket was empty because the procedure ran pg_dump 9.2 against PostgreSQL 9.6, which it treats as a major-version mismatch, on an application server where Omnibus saw no PG_VERSION and defaulted to 9.2. Cron mail was the signal for that failure. It missed the failure because DMARC was not enabled for those messages and the receiver rejected them. Azure disk snapshots were on for the NFS servers and not for any database server; the postmortem says other backup procedures were assumed to be enough. Replication could not be a failover copy either: the secondary’s data directory had been wiped to rebuild it, and WAL segments the secondary needed were already gone because GitLab.com was not using WAL archiving. What remained was the LVM snapshot taken at about 17:20 UTC and loaded into staging. Copying that staging data to production took around 18 hours. The postmortem says those Azure classic disks were throttled to around 60 Mbps, that there was no network or processor bottleneck, and that the bottleneck was the drives. The log line dated 2017/02/01 04:00, which does not print a timezone, says the transfer was slowed by two factors, network I/O between us-east and us-east-2 and a disk throughput cap of 60 Mb/s. Neither sentence is a measured byte rate. The postmortem says the database was restored without webhooks at 17:00 UTC on 1 February and that final procedures, including webhooks, finished around 18:00 UTC. The log prints 2017/02/02 16:28 for transfer complete, on a capture whose URL is timestamped 2017-02-02 03:47:19 UTC. A separate log estimate, ±20 hours, refers to an initial pg_basebackup sync while staging was being set up, not to this production copy.
What the log can prove is the text it printed, not which rows stayed gone. The user figure is a Kibana estimate: 707 users lost potentially, hard to tell for certain. The project total is explicitly rough, and the same sentence says Git repositories were not lost, so projects whose user or group already existed could be recreated without their issues. In that capture, creating those project records is still an open checklist item. By the 10 February postmortem, a procedure had restored projects from Git repositories still on the NFS cluster, only in basic form, without issues or merge requests, and the exact loss was still described as hard to estimate. The 5,000 and 5,037 figures are therefore not a count of objects that remained absent. No issue count, snippet count, merge-request count, or webhook count is printed. The log says webhooks created before 17:20 on 31 January were restored and later ones were lost. The Register prints that cutoff as 5.20pm with no timezone in the bullet. The postmortem’s recovery steps say the process would increment sequences by 100,000. The log checks off an increment of 10k. This page does not decide which increment ran, and it does not treat either document as a census.
This is one public outage on 31 January 2017, not a drive census. Other measurements are on the analyses index.
Sources
- 01Postmortem of database outage of January 31, GitLab, published 10 February 2017. Vendor narrative of the GitLab.com primary/secondary pair. No data license is stated on the page. · accessed 2026-10-12
- 02GitLab.com Database Incident - 2017/01/31, public incident log as captured by the Internet Archive at 2017-02-02 03:47:19 UTC. The live Google document was not opened. · accessed 2026-10-12
- 03GitLab.com luckily found lost data on a staging server, Simon Sharwood, The Register, 2 February 2017, 05:57 UTC. Quotes the incident log and a GitLab PR line. · accessed 2026-10-12