windmill-labs/windmill · error
HTTP ${res.status} ${res.statusText}
Error message
HTTP ${res.status} ${res.statusText} What it means
Thrown by fetchRecording when the HTTP response for the recording URL is not ok — it surfaces the raw status and statusText from the server hosting the recording file. 404 means the file is gone, 401/403 an access problem, 5xx a server failure; the recording never starts downloading.
Source
Thrown at frontend/src/lib/components/recording/rawAppRecordingLoad.ts:613
// `type` is caller-controlled and only structurally bounded: a payload can
// carry megabytes in it and reach the page as text. Name it only when it is
// short enough to be a kind rather than a payload.
const named = typeof type === 'string' && type.length <= 32 ? ` (${type})` : ''
return {
ok: false,
error: `This recording is of an unknown kind${named} — it may need a newer Windmill.`
}
}
}
}
/** Fetch a recording from `url`, enforcing the download cap while streaming. */
export async function fetchRecording(
url: string,
onProgress?: (loaded: number, total: number) => void
): Promise<unknown> {
const res = await fetch(url)
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`)
const total = Number(res.headers.get('content-length')) || 0
if (total > MAX_RECORDING_BYTES) throw new Error(`Recording is too large (${total} bytes)`)
const reader = res.body?.getReader()
if (!reader) {
const text = await res.text()
if (text.length > MAX_RECORDING_BYTES) throw new Error('Recording exceeded the size limit')
return JSON.parse(text)
}
const chunks: Uint8Array[] = []
let loaded = 0
for (;;) {
const { done, value } = await reader.read()
if (done) break
if (!value) continue
chunks.push(value)
loaded += value.length
if (loaded > MAX_RECORDING_BYTES) {
await reader.cancel()View on GitHub (pinned to e474e8803c)
Solutions
- Check the URL is correct and still points at an existing recording file
- Re-capture or re-export the recording if the source run/file is gone
- Verify permissions/authentication for the storage serving the file
Defensive patterns
Strategy: retry
Validate before calling
const head = await fetch(url, { method: 'HEAD' })
if (!head.ok) throw new Error(`Recording unavailable: ${head.status}`) Type guard
function isOk(res: Response): res is Response & { ok: true } { return res.ok } Try / catch
try { rec = await fetchRecording(url) } catch (e) { if (/^HTTP \d+/.test(String(e))) notify('Recording unavailable at ' + url); else throw e } Prevention
- Validate share URLs before storing them
- Use stable, permissioned storage for recordings
- Surface HTTP status to the user rather than a generic failure
When it happens
Trigger: fetchRecording(url) where the server returns 404 (file removed), 403 (no permission), 500, or any non-2xx status.
Common situations: A recording URL from an old share link whose underlying file was deleted; expired signed storage URL; wrong workspace/base URL in the link.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- body.error || res.statusText
- ${response.status} ${text}
- GET /assets/graph → ${res.status}
- ApiError with mapped HTTP status message (e.g. "Not Found",
- Generic Error: status: ${errorStatus}; status text: ${errorS
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/d0cc410c3544dcfe.
Report an issue: GitHub.