Repository navigation
fix: sign-in 500 — auth rate limit passed raw Date params to postgres.js - #93
Conversation
Every sign-in and sign-up attempt returned HTTP 500 in production: TypeError: The "string" argument must be of type string or an instance of Buffer or ArrayBuffer. Received an instance of Date postgres.js cannot serialize a raw Date interpolated into a drizzle `sql` fragment - only drizzle's own column-typed bindings get mapped. The atomic rate-limit upsert interpolated two Date objects directly, so the statement failed before credentials were ever checked. Pre-stringify the timestamps to ISO and cast them back to timestamptz inside the statement. The upsert stays a single atomic statement that increments in the database. Verified against a real Postgres 16 instance: insert path, conflict/upsert path, atomic increment to count=5, throttling engaging, and a full sign-up -> wrong-password-401 -> correct-password-200 flow.
Strix Security ReviewNo security issues found. Review summaryReviewed both changed files: the rate-limiter fix in Updated for Reviewed by Strix |
Problem
Every sign-in and sign-up attempt on production returned HTTP 500 ("Request failed" in the UI). From the Coolify app logs:
This was not a credentials problem — the request died in the rate limiter before credentials were ever checked, so no one could log in at all.
Root cause
postgres.js cannot serialize a raw
Datethat is interpolated into a drizzlesqlfragment; only drizzle's own column-typed bindings get mapped to a driver-serializable value. The atomic upsert introduced infix: make auth rate limit increments atomicinterpolatedwindowStartandexpiredBeforeDateobjects directly into thecase when ...fragments.Fix
Pre-stringify both timestamps to ISO and cast them back to
timestamptzinside the statement. The upsert remains a single atomic statement that incrementscountin the database, so the original security-review fix still holds.Tests
Added
tests/auth/rate-limit-params.test.ts, which drives the real rate-limit module through drizzle's pg-proxy driver and asserts:Dateever reaches the driver (this test fails on the old code with the exact 3 offending params)on conflictupsert with an in-database"count" + 1Verification
yarn lint✅yarn test:run✅ 68 files / 291 testscount=5, throttling engaging withretryAfterSeconds=900, and a fullsign-up→ wrong-password401→ correct-password200flow.