windmill-labs/windmill · error · Error

the hub proxy answered ${res.status}

Error message

the hub proxy answered ${res.status}

What it means

ImportSetupStep fetches a hub project export through the workspace's hub proxy endpoint. Any non-2xx response from the proxy (auth failure, hub unreachable, unknown project slug) is converted into this Error, so the UI shows the raw HTTP status rather than a silent failure.

Source

Thrown at frontend/src/lib/components/ImportSetupStep.svelte:267

		absent: boolean,
		prev: Row | undefined
	): Promise<Row['status']> {
		if (absent) return 'unconfigured'
		const applied = await probeMigrationsApplied(workspace, name, ms)
		if (applied === true) return 'done'
		if (applied === false) return prev?.status === 'failed' ? 'failed' : 'unconfigured'
		return prev?.status === 'failed' ? 'failed' : 'unknown'
	}

	/** Which data tables the project needs that the destination does not have yet. */
	async function load() {
		loading = true
		loadError = undefined
		try {
			const res = await fetch(
				`/api/w/${encodeURIComponent(workspace)}/hub/projects/${encodeURIComponent(slug)}/export`
			)
			if (!res.ok) throw new Error(`the hub proxy answered ${res.status}`)
			const exportData = (await res.json()) as ProjectExport
			const enabled = (exportData.migrations ?? []).filter(
				(m) => m.enabled && (m.sql ?? '').trim() !== ''
			)
			// Kept, not just counted: which data tables the destination has decides whether a
			// row can retry its migrations or has to go back through the wizard, and after a
			// reload this call is the only thing that knows. Drop it and such a row offers the
			// wizard, which then refuses the name it created itself.
			const tables = await WorkspaceService.listDataTables({ workspace })
			configuredNames = tables.map((t) => ({ name: t.name, resourcePath: t.resource_path }))
			const present = new Set(tables.map((d) => d.name))
			const missing = [...new Set(enabled.map((m) => m.datatable_name))].filter(
				(n) => !present.has(n)
			)
			const previous = new Map(rows.map((r) => [r.name, r]))
			rows = await Promise.all(
				[...new Set(enabled.map((m) => m.datatable_name))].map(async (name) => {
					const ms = enabled.filter((m) => m.datatable_name === name)

View on GitHub (pinned to e474e8803c)

Solutions

  1. Check the reported HTTP status: 404 means the slug is wrong or the project no longer exists — verify the slug on the hub
  2. 401/403: re-authenticate the workspace against the hub (re-link credentials) and retry
  3. 5xx/502: retry later; check hub.windmill.dev availability and backend logs for proxy errors
  4. Verify network egress from the Windmill backend instance to the hub

Example fix

// before
const res = await fetch(`/api/w/${workspace}/hub/projects/${slug}/export`)
if (!res.ok) throw new Error(`the hub proxy answered ${res.status}`)
// after
const res = await fetch(`/api/w/${workspace}/hub/projects/${slug}/export`)
if (!res.ok) {
  const detail = await res.text().catch(() => '')
  throw new Error(`Hub export failed (${res.status}): ${detail || res.statusText}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before loading, check the slug is a plausible string
if (!slug || typeof slug !== 'string') throw new Error('Missing hub project slug')

Type guard

function isOkResponse(res: Response): boolean { return res.ok }

Try / catch

try {
  const res = await fetch(`/api/w/${workspace}/hub/projects/${slug}/export`)
  if (!res.ok) throw new Error(`the hub proxy answered ${res.status}`)
  const exportData = await res.json()
} catch (e) {
  loadError = String(e.message)
  sendUserToast(`Hub project export failed: ${e.message}`, true)
}

Prevention

When it happens

Trigger: fetch(`/api/w/<workspace>/hub/projects/<slug>/export`) returns res.ok === false — e.g. 404 when the hub slug does not exist, 401/403 on expired credentials, or 502/504 when the hub proxy cannot reach the hub.

Common situations: Typo in the imported project slug; the hub project was renamed or deleted; the workspace's hub token expired; network/proxy outage between the Windmill backend and hub.windmill.dev.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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