{"record":{"id":"3d346f717c1e861c","repo":"clockworklabs/SpacetimeDB","slug":"timestamp-before-unix-epoch-3d346f","errorCode":null,"errorMessage":"timestamp before unix epoch","messagePattern":"timestamp before unix epoch","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"crates/bindings-csharp/BSATN.Runtime/BSATN/Uuid.cs","lineNumber":137,"sourceCode":"    public static Uuid FromCounterV7(\n        ref int counter,\n        Timestamp now,\n        ReadOnlySpan<byte> randomBytes // must be length 4\n    )\n    {\n        if (randomBytes.Length != 4)\n        {\n            throw new ArgumentException(\"randomBytes must be exactly 4 bytes\", nameof(randomBytes));\n        }\n\n        if (counter < 0)\n        {\n            throw new InvalidOperationException(\"uuid counter must be non-negative\");\n        }\n\n        if (now.MicrosecondsSinceUnixEpoch < 0)\n        {\n            throw new ArgumentException(\"timestamp before unix epoch\", nameof(now));\n        }\n        var unixTsMs = now.MicrosecondsSinceUnixEpoch / 1_000;\n\n        // monotonic 31-bit\n        var counterVal = counter;\n        counter = (counter + 1) & 0x7FFF_FFFF;\n\n        Span<byte> bytes = stackalloc byte[16];\n\n        // unix_ts_ms (48 bits, big-endian)\n        var ts = unixTsMs & 0x0000_FFFF_FFFF_FFFFL;\n        bytes[0] = (byte)(ts >> 40);\n        bytes[1] = (byte)(ts >> 32);\n        bytes[2] = (byte)(ts >> 24);\n        bytes[3] = (byte)(ts >> 16);\n        bytes[4] = (byte)(ts >> 8);\n        bytes[5] = (byte)ts;\n","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/bindings-csharp/BSATN.Runtime/BSATN/Uuid.cs#L119-L155","documentation":"Thrown by Uuid.FromCounterV7 when the passed Timestamp is before 1970-01-01T00:00:00 UTC. UUIDv7 embeds a 48-bit unix_ts_ms field which cannot represent negative unix time, so the library rejects pre-epoch timestamps via ArgumentException on the `now` parameter.","triggerScenarios":"Passing a Timestamp converted from a DateTimeOffset/DateTime before 1970 (historical dates, birthdates, zeroed DateTime values interpreted oddly); a machine clock set before the epoch; arithmetic on MicrosecondsSinceUnixEpoch that underflows below zero.","commonSituations":"Batch-importing historical records and generating IDs from their dates; misconfigured VM/container clocks; test fixtures with fixed pre-epoch dates.","solutions":["Pass the current time (Timestamp.UtcNow / DateTimeOffset.UtcNow conversion) instead of the entity's business date","If you must derive from a date, clamp it: now < epoch ? epoch : now","Fix the system clock / NTP configuration if the machine reports pre-epoch time","Validate ts.MicrosecondsSinceUnixEpoch >= 0 before calling and log the offending source value"],"exampleFix":"// before\nvar ts = new Timestamp(new DateTimeOffset(1969, 7, 20, 0, 0, 0, TimeSpan.Zero));\nvar id = Uuid.FromCounterV7(ref counter, ts, rand4); // throws\n\n// after\nvar now = Timestamp.UtcNow; // IDs use generation time, not business dates\nvar id = Uuid.FromCounterV7(ref counter, now, rand4);","handlingStrategy":"validation","validationCode":"static Timestamp ClampToEpoch(Timestamp ts) =>\n    ts.MicrosecondsSinceUnixEpoch < 0 ? new Timestamp(0) : ts;\n\nvar id = Uuid.FromCounterV7(ref counter, ClampToEpoch(now), randomBytes);","typeGuard":null,"tryCatchPattern":"try\n{\n    id = Uuid.FromCounterV7(ref counter, now, randomBytes);\n}\ncatch (ArgumentException ex) when (ex.ParamName == \"now\")\n{\n    logger.LogWarning(\"Pre-epoch timestamp {Ts} clamped for UUIDv7\", now);\n    id = Uuid.FromCounterV7(ref counter, new Timestamp(0), randomBytes);\n}","preventionTips":["Derive ID timestamps from generation time (UtcNow), never from business/historical dates","In tests, use fixed dates after 1970","Validate clock sanity at startup (reject MicrosecondsSinceUnixEpoch < 0 from the environment)"],"tags":["csharp","uuid","uuidv7","timestamp","argument-validation"],"backgroundTag":"timestamp-before-epoch","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}