Skip to content

fix: transient error matching, usage month boundary and webhook signature compare - #4

Open
manpreet171 wants to merge 1 commit into
jayasukuv11-beep:mainfrom
manpreet171:fix/small-correctness-bugs
Open

fix: transient error matching, usage month boundary and webhook signature compare#4
manpreet171 wants to merge 1 commit into
jayasukuv11-beep:mainfrom
manpreet171:fix/small-correctness-bugs

Conversation

@manpreet171

Copy link
Copy Markdown

Four small independent fixes found while reading through the codebase.

isTransientError()lib/brain/retry.ts

const message =
  error instanceof Error ? error.message : String(error || "").toLowerCase()

.toLowerCase() binds to the else branch only, so for a real Error the message keeps its casing. The non-transient keyword list right below is all lowercase, so "unauthorized", "conflict" and "validation" never matched an Error. An error like Request Timeout: Unauthorized upstream fell through to the transient patterns and got retried three times with backoff.

The existing tests only pass lowercase messages, so this stayed green. Added a case that covers it.

Usage month boundary — lib/usage.ts

new Date(y, m, 1).toISOString() builds the boundary from the server's local midnight. On a UTC+5:30 host that resolves to Jun 30 18:30Z, pulling five and a half hours of the previous month's credit_usage into the current month's totals. Switched to Date.UTC, matching the created_at timestamps being compared against.

Webhook signature compare — app/api/webhooks/cashfree/route.ts

!== on an HMAC compares byte by byte and returns early. Switched to crypto.timingSafeEqual with a length guard, since it throws on mismatched lengths.

Gemini key fallback — app/api/sdk/evals/judge/route.ts

The route fell back to a key literal in the source when GEMINI_API_KEY was unset. Removed it and moved the lookup out of the loop so the route returns a config error instead of sending an unusable request per criterion.

Full suite: 167 passed, and tsc --noEmit is clean.

…ompare

- isTransientError() only lowercased the non-Error branch, so the
  non-transient keyword list never matched a real Error. Auth and
  validation failures could be retried when the message also looked
  transient.
- getUserUsage() built the month boundary in server local time, so on a
  non-UTC host the window included part of the previous month.
- The Cashfree webhook compared signatures with !==. Switched to
  timingSafeEqual with a length guard.
- Dropped the hardcoded Gemini key fallback in the judge route and fail
  with a config error when GEMINI_API_KEY is unset.
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

@manpreet171 is attempting to deploy a commit to the tharagesh's projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant