flashman
← All posts

Snowflake id epoch debugging

Debug a snowflake id whose clock is years off by naming its epoch, shifting away the low 22 bits, and keeping the full decimal id as a string in JSON.

2026-10-16 · 7 min read · Rahul Chitturi

  • identifiers
  • json
  • time

A snowflake is a 64-bit integer whose high bits are a millisecond clock and whose low bits are a generator id and a sequence. The clock is not Unix time. It is milliseconds since an epoch the generator chose. Twitter's layout uses 1288834974657, which is 2010-11-04T01:42:54.657Z. Discord's layout uses 1420070400000, which is 2015-01-01T00:00:00.000Z. Both shift 22 bits to reach the time.

Applying the Discord epoch to a Twitter-layout id moves the instant by about four years. The id is not corrupt. The epoch is the wrong constant.

Shift 22 bits, then add the epoch you named

A constructed Twitter-layout id 1724551110456668202 has datacenter 3, worker 7, and sequence 42. Shift it right by 22 and add 1288834974657 and the clock is 1700000000000, which is 2023-11-14T22:13:20.000Z. Add 1420070400000 instead and the same bits read as 2028-01-11T20:30:25.343Z.

Discord's published example 175928847299117063 shifts the same way with the 2015 epoch: 1462015105796 milliseconds, which is 2016-04-30T11:18:25.796Z, worker 1, process 0, increment 7. The low 12 bits are the sequence, the next 5 and 5 are the two generator fields, and everything above bit 21 is the clock. Write those widths down next to the epoch. A layout that uses a different split is a different id, even if the column is also called a snowflake.

  • Keep the original decimal text. Do not parse it as a JavaScript number.
  • Name the epoch in the same note as the shift.
  • Mask the low 22 bits only after the time matches a known row.
  • Do not treat the id as a secret. The timestamp is visible.

JSON numbers drop the sequence and keep the clock

A JSON number is an IEEE double. Integers past 2^53 − 1 are not all representable. Number("1724551110456668202") is the integer 1724551110456668160. The high bits still decode to 2023-11-14T22:13:20.000Z, and the sequence becomes 0. The clock looks right while the id no longer equals the string the API sent.

Flashman's JSON formatter shows whether the field is a string or a number. The timestamp converter takes Unix seconds: divide the millisecond clock by 1000 and paste the integer part, 1700000000 for that example. It will misread a raw millisecond count as seconds. The UUID tool mints version 4 ids only. The number-base tool uses parseInt and is not safe for the full 64-bit value; use it only on the small worker or sequence field after you have masked it. Diff the original string against the value a client actually stored.

Try these tools