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

  1. Check the URL is correct and still points at an existing recording file
  2. Re-capture or re-export the recording if the source run/file is gone
  3. 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

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


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/d0cc410c3544dcfe. Report an issue: GitHub.