diff --git a/packages/app/src/app/api/v1/benchmarks/route.ts b/packages/app/src/app/api/v1/benchmarks/route.ts index c79f1aa74..9e9641820 100644 --- a/packages/app/src/app/api/v1/benchmarks/route.ts +++ b/packages/app/src/app/api/v1/benchmarks/route.ts @@ -20,10 +20,16 @@ const getCachedBenchmarks = cachedQuery( { blobOnly: true }, ); +const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/u; + export async function GET(request: NextRequest) { const params = request.nextUrl.searchParams; const model = params.get('model') ?? ''; - const date = params.get('date') ?? undefined; + // Reject anything that isn't an ISO YYYY-MM-DD — otherwise postgres-js will + // coerce `${date}::date` via `new Date(date)`, which on garbage produces NaN + // and throws `Invalid time value` from toISOString → opaque 500. + const rawDate = params.get('date'); + const date = rawDate && ISO_DATE_RE.test(rawDate) ? rawDate : undefined; const exact = params.get('exact') === 'true'; const dbModelKeys = DISPLAY_MODEL_TO_DB[model]; if (!dbModelKeys || dbModelKeys.length === 0) { diff --git a/packages/app/src/hooks/api/use-benchmarks.ts b/packages/app/src/hooks/api/use-benchmarks.ts index 6da1568e3..2087c27db 100644 --- a/packages/app/src/hooks/api/use-benchmarks.ts +++ b/packages/app/src/hooks/api/use-benchmarks.ts @@ -9,9 +9,15 @@ export function benchmarkQueryOptions( enabled = true, exact?: boolean, ) { + // 'latest' is only a queryKey marker meaning "no specific date" — must NOT + // be sent to the API as a date filter (postgres-js coerces `${date}::date` + // params via `new Date(date)`, which on 'latest' produces NaN and throws + // `Invalid time value` from toISOString → 500 to the client). + const dateForFetch = date === 'latest' ? undefined : date; return { queryKey: ['benchmarks', model, date, exact ? 'exact' : 'latest'] as const, - queryFn: ({ signal }: { signal: AbortSignal }) => fetchBenchmarks(model, date, exact, signal), + queryFn: ({ signal }: { signal: AbortSignal }) => + fetchBenchmarks(model, dateForFetch, exact, signal), enabled: enabled && Boolean(model), }; }