Tides route caps days at 14 and says so
Origin: authoredStatus: confirmedRepo: tidewatch-apiCard: TW-212Branch: tw-212-days-limitWritten: 19 Sept 2026Size: 9 files, +171 -22 (large: lines, files)
What
The tides route now refuses days above 14 with a 400 that states the range. Before, any number was accepted and a request for a year of tides was computed in full.
Cites
Why
Card TW-212: one client asked for 365 days per station every night and each call held a worker for about 40 seconds. The cap is the smallest change that stops that without touching the prediction code.
Cites
How
parseTideQuery validates days as a whole number from 1 to MAX_DAYS before anything is computed, and returns the message with the limit in it so the client can fix itself.
What breaks
Any client asking for more than 14 days now gets 400 instead of data. They have to page by date. Responses for 1 to 14 days are unchanged.
Alternatives
Streaming long ranges was considered and left for later: it keeps the worker busy just as long. A per-plan limit was rejected for now because only one client is affected.
Cites
Believed before
days is unbounded, ask for as many as you like.
True now
days is 1 to 14. Page by date for longer ranges.
Cites
- [1]src/routes.ts:4-13matchSupports: what[lines 4-13 of a 16-line file]
const MAX_DAYS = 14;// GET /v1/stations/:id/tides?from=YYYY-MM-DD&days=Nexport function parseTideQuery(id: string, from: string, days: string | undefined) {const station = getStation(id);if (!station) return { status: 404 as const, error: `Unknown station: ${id}` };const n = days === undefined ? 1 : Number(days);if (!Number.isInteger(n) || n < 1 || n > MAX_DAYS) {return { status: 400 as const, error: `days must be a whole number from 1 to ${MAX_DAYS}` };} - [2]src/routes.ts:10-12matchSupports: why[lines 10-12 of a 16-line file]
const n = days === undefined ? 1 : Number(days);if (!Number.isInteger(n) || n < 1 || n > MAX_DAYS) {return { status: 400 as const, error: `days must be a whole number from 1 to ${MAX_DAYS}` }; - [3]src/rate-limit.ts:1-3matchSupports: alternatives[lines 1-3 of a 8-line file]
// Fixed window, per API key. The window is one minute and the limit is per plan.export const LIMITS = { free: 30, harbour: 300 } as const;export type Plan = keyof typeof LIMITS;
Card
What is the most days of tides one request can ask for, and what happens above it?
juniorShow the answerHide the answer
14. Above that the route returns 400 naming the 1 to 14 range, and nothing is computed.
Cites[1]
Questions
junior
Where is the days limit enforced?
juniorShow the answerHide the answer
In parseTideQuery in src/routes.ts, before any prediction is computed.
Cites[1]
mid
Why a hard cap rather than streaming the long range?
midShow the answerHide the answer
Streaming keeps the worker busy for just as long. The problem was worker time, so the cap fixes it and streaming does not.
Cites[2]