ruvnet/ruflo · warning · Error
Received empty response from ${url} but allowNull is not set
Error message
Received empty response from ${url} but allowNull is not set to true What it means
Thrown by fetchJSON when the response was OK (2xx) but the body parsed to empty (no text or whitespace-only). Because the generic return type T is non-null, a null result is only allowed when the caller explicitly opts in via options.allowNull === true; otherwise the helper refuses to return null as T.
Source
Thrown at ruflo/src/ruvocal/src/lib/utils/fetchJSON.ts:19
export async function fetchJSON<T>(
url: string,
options?: {
fetch?: typeof window.fetch;
allowNull?: boolean;
}
): Promise<T> {
const response = await (options?.fetch ?? fetch)(url);
if (!response.ok) {
throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
}
// Handle empty responses (which parse to null)
const text = await response.text();
if (!text || text.trim() === "") {
if (options?.allowNull) {
return null as T;
}
throw new Error(`Received empty response from ${url} but allowNull is not set to true`);
}
return JSON.parse(text);
}
View on GitHub (pinned to 6b01dc5a68)
Solutions
- If an empty/204 response is valid for this call, pass { allowNull: true } and handle T | null at the call site.
- If the endpoint should return JSON, fix the server to return a real body (or a proper 404).
- Check for an intercepting proxy (nginx try_files, a CDN) that is replacing the body with an empty page.
- Confirm Content-Type and that no middleware is converting 204 into 200-with-empty.
Example fix
// before
const data = await fetchJSON<MyType>(`${base}/api/thing/${id}`);
// after
const data = await fetchJSON<MyType | null>(`${base}/api/thing/${id}`, { allowNull: true });
if (data === null) return null; Defensive patterns
Strategy: validation
Validate before calling
// decide based on the endpoint's contract before calling
const allowsEmpty = endpointReturnsEmptyOnSuccess(url);
const data = await fetchJSON<T | null>(url, { allowNull: allowsEmpty });
if (data === null && !allowsEmpty) throw new Error(`unexpected null from ${url}`); Try / catch
try {
return await fetchJSON<T>(url); // allowNull omitted intentionally
} catch (e) {
if (String((e as Error)?.message ?? "").includes("allowNull is not set to true")) {
return null as T; // empty body is valid for this caller
}
throw e;
} Prevention
- Document which endpoints return 204/empty and pass allowNull:true for exactly those.
- Prefer fixing the server to return a real JSON body (or a proper 404) over silencing the guard.
- In tests, assert that endpoints expected to return data never return an empty body.
When it happens
Trigger: An endpoint returns 200 with an empty body (or 204 No Content with no body) — common for DELETE, ack-style POSTs, or a misconfigured proxy that strips the body. The caller did not pass allowNull: true.
Common situations: Calling a REST endpoint that legitimately returns 204; a backend that returns 200 + empty when a resource is not found instead of a real 404; switching fetchJSON to point at an endpoint whose contract is "empty on success".
Related errors
- Failed to fetch ${url}: ${response.status} ${response.status
- unknown game "${key}". Known: ${Object.keys(GAMES).join(', '
- unknown strategy "${name}". Available: ${roster.map((r) => r
- Failed to create share link
- Invalid completion type
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/56bfd604b6c1ca23.
Report an issue: GitHub.