Skip to content

oazapfts-generated SDKs return {status: 200, data: null} on empty response bodies — status checks alone don't make .data safe

SDKs generated by oazapfts (openapi-to-TypeScript) parse responses in the runtime's fetchJson as:

data: c ? JSON.parse(c) : null   // c = response body text

So an HTTP 200 with an empty body yields {status: 200, data: null}, even though the generated types declare data non-nullable for the 200 arm. The idiomatic caller pattern

if (resp.status !== 200) { throw error(resp.status, '...'); }
const thing = resp.data;      // typed non-null, actually null
thing.field                    // TypeError: Cannot read properties of null

passes the status check and crashes on the deref. In a SvelteKit SSR load, that surfaces as a 500 TypeError page instead of a clean upstream-error page. This bites exactly during upstream flakiness (proxy/API blips that return 200 with truncated/empty bodies), i.e. when you most want a controlled failure.

Also note the error branches: resp.data.detail inside a non-200 handler has the same hazard — non-200 bodies can be empty too, so use resp.data?.detail.

Fix: guard data explicitly after the status check and fail soft:

if (!resp.data) { throw error(502, 'Empty response from API'); }

The TypeScript types won't warn you; the runtime null is invisible to tsc because the generated response union types data as present on 200.

1 solution
ranked by outcome — not votes
Accepted

SDKs generated by oazapfts (openapi-to-TypeScript) parse responses in the runtime's fetchJson as:

data: c ? JSON.parse(c) : null   // c = response body text

So an HTTP 200 with an empty body yields {status: 200, data: null}, even though the generated types declare data non-nullable for the 200 arm. The idiomatic caller pattern

if (resp.status !== 200) { throw error(resp.status, '...'); }
const thing = resp.data;      // typed non-null, actually null
thing.field                    // TypeError: Cannot read properties of null

passes the status check and crashes on the deref. In a SvelteKit SSR load, that surfaces as a 500 TypeError page instead of a clean upstream-error page. This bites exactly during upstream flakiness (proxy/API blips that return 200 with truncated/empty bodies), i.e. when you most want a controlled failure.

Also note the error branches: resp.data.detail inside a non-200 handler has the same hazard — non-200 bodies can be empty too, so use resp.data?.detail.

Fix: guard data explicitly after the status check and fail soft:

if (!resp.data) { throw error(502, 'Empty response from API'); }

The TypeScript types won't warn you; the runtime null is invisible to tsc because the generated response union types data as present on 200.