{"UUID":"9dbf5bb5-79ba-4d1f-8d14-d6f0ca264fd6","URL":"https://incident.io/blog/one-two-skip-a-few","ArchiveURL":"","Title":"incident.io incident ID sequence jump","StartTime":"0001-01-01T00:00:00Z","EndTime":"0001-01-01T00:00:00Z","Categories":["config-change"],"Keywords":["postgresql","sequence","nextval","incident ids","database upgrade","high availability","wal","incident.io"],"Company":"incident.io","Product":"incident ID generation","SourcePublishedAt":"2021-07-12T00:00:00Z","SourceFetchedAt":"2026-05-04T19:52:02.661356Z","Summary":"Customers noticed their per-organization `INC-N` IDs jumping by exactly 32 (e.g. `#INC-7` directly to `#INC-39`) after a Postgres HA upgrade that promoted a follower to primary. Postgres's `nextval` pre-allocates `SEQ_LOG_VALS = 32` sequence values on the WAL to avoid logging every `nextval`; a follower sees the post-crash state, so when promoted the sequence jumps forward by up to 32. Fix was to replace `nextval` with a `SELECT MAX(external_id)+1` trigger.","Description":"Customers of incident.io began reporting that their per-organization incident identifiers, such as #INC-N, were unexpectedly jumping. For example, one customer observed an ID jump from #INC-7 directly to #INC-39, indicating a consistent skip of 32 numbers. This suggested a systematic issue with how incident IDs were being generated.\n\nInitially, the team considered transaction rollbacks as a potential cause, as PostgreSQL sequences increment even if a transaction is rolled back. However, this was deemed unlikely because it would require 32 failed incident creations for a single organization, and no such issues or customer reports of failed incident creation were observed.\n\nThe root cause was identified in PostgreSQL's sequence behavior. PostgreSQL pre-allocates 32 values (`SEQ_LOG_VALS`) to optimize Write-Ahead Log (WAL) writes, avoiding logging every `nextval` call. During a database upgrade, a follower node was promoted to become the new primary. When this promotion occurred, the new primary assumed all pre-allocated values on the previous primary had been used, causing the sequence to effectively \"skip\" up to 32 values forward.\n\nWhile no data was lost or misattributed, the unexpected jumps in incident IDs were confusing for customers. To resolve this, incident.io modified their ID generation logic. Instead of relying on `nextval` from a PostgreSQL sequence, they implemented a trigger that explicitly calculates the next `external_id` by querying `SELECT COALESCE(MAX(external_id), 0) + 1` for the specific organization, ensuring strictly sequential and gap-free IDs."}