Skip to content

Paper note

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 figures for the GitLab.com database outage of 31 January 2017. Columns are Printed figure, Value (as printed), Unit, Claim label, and Source. The population is one PostgreSQL primary (db1.cluster.gitlab.com) and one hot-standby secondary (db2.cluster.gitlab.com). Sources are the vendor postmortem published 10 February 2017, the incident log captured at 2017-02-02 03:47:19 UTC, and The Register on 2 February 2017 at 05:57 UTC. Each row is one sentence. The Register’s hour, project, comment, and user rows quote the log and are not a second measurement. Around 60 Mbps and 60 Mb/s are a stated throttle and a stated cap, not a measured throughput, and they are not converted. Percent rows are progress at a clock, not a rate. The three rows near 18 hours are three sentences. Git repositories and wikis are not in the lost database rows. No issue, snippet, or merge-request count is printed, so none is added.
Printed figureValue (as printed)UnitClaim labelSource
Loss-window end, postmortem introduction (same sentence also names 17:20 UTC on 31 January)00:00UTC on 31 January 2017Vendor claimGitLab postmortem
Loss-window end, postmortem data-loss section (same sentence also names 17:20 UTC)23:30UTC on 31 January 2017Vendor claimGitLab postmortem
LVM snapshot of the production database, postmortem timeline±17:20UTC on 31 January 2017Vendor claimGitLab postmortem
Removal on the primary, postmortem timeline±23:30UTC on 31 January 2017Vendor claimGitLab postmortem
Removal terminated, incident-log timeline23:27UTC on 31 January 2017Vendor incident logIncident log
Loss duration, incident-log impact list±6hoursVendor incident logIncident log
Loss duration, The Register quoting the impact listabout 6hoursNews quotation of the incident logThe Register
Projects, postmortem introduction (best estimate)roughly 5,000projectsVendor claimGitLab postmortem
Projects, postmortem data-loss sectionat least 5000projectsVendor 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)5037projects, labeled roughlyVendor 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 list5,037projectsNews quotation of the incident logThe Register
Comments, postmortem introduction (same best-estimate sentence as the projects)5,000commentsVendor claimGitLab postmortem
Comments, postmortem data-loss section5000commentsVendor claimGitLab postmortem
Comments, incident-log impact list±4979 (so ±5000)commentsVendor incident logIncident log
Comments, The Register quoting the impact listabout 4,979commentsNews quotation of the incident logThe Register
Users, postmortem introduction700new user accountsVendor claimGitLab postmortem
Users, postmortem data-loss sectionroughly 700usersVendor claimGitLab postmortem
Users, incident-log impact list707usersVendor incident log. Potentially, hard to tell for certain from the Kibana logs.Incident log
Users, The Register quoting the impact list707usersNews quotation of the incident logThe Register
Users, The Register standfirst~707usersNews 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 lineless than 1percent of user baseVendor 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 timelinearound 300GBVendor claimGitLab postmortem
Size named when the removal was terminated, incident-log timelinearound 310GBVendor 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 timelineabout 4.5GBVendor incident logIncident log
Staging-to-production copy, postmortem recovery narrativearound 18hoursVendor claim. A duration, not a throughput.GitLab postmortem
Downtime, postmortem 5 Whys, problem 1about 18hoursVendor claim. Not the copy-duration sentence.GitLab postmortem
Time to restore, postmortem 5 Whys, problem 2over 18hoursVendor claim. Not the copy-duration sentence.GitLab postmortem
Azure classic disk throttle, postmortem recovery narrativearound 60MbpsVendor 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:0060Mb/sVendor 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:00approximately 50percent of filesVendor incident log. Progress snapshot, not a rate.Incident log
rsync progress, incident log line dated 2017/02/01 04:00approximately 56.4percent of filesVendor incident log. Progress snapshot, not a rate.Incident log
Transfer progress, incident log line dated 2017/02/01 08:0742percent of data sizeVendor incident log. Different denominator from the file-count percents. Not a rate.Incident log
Database restored without webhooks, postmortem recovery narrative17:00UTC on 1 February 2017Vendor claimGitLab postmortem
Final restoration procedures finished, postmortem recovery narrativearound 18:00UTC clock timeVendor 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 log2017/02/02 16:28clock time as printedVendor 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±20hoursVendor incident log. An estimate for that sync, not the production copy of around 18 hours.Incident log
Sequence increment, postmortem recovery steps100,000sequence incrementVendor claim. Listed among steps the process would involve. Not shown here as a confirmed applied value.GitLab postmortem
ID increment, incident-log restore checklist10kID incrementVendor incident log. Checkbox marked done. Printed as 10k and not expanded on this page.Incident log
pg_dump binary used for the daily backup, postmortem9.2PostgreSQL versionVendor claim. Run where no data directory made Omnibus default to 9.2. The S3 bucket was empty.GitLab postmortem
Production database, postmortem9.6PostgreSQL versionVendor 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 list17:20clock time as printed (Jan 31st 17:20); the impact bullet does not say UTCVendor 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 log5.20pmclock time as printed, no timezone in that bulletNews 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

  1. 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
  2. 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
  3. 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