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
- Check the reported HTTP status: 404 means the slug is wrong or the project no longer exists — verify the slug on the hub
- 401/403: re-authenticate the workspace against the hub (re-link credentials) and retry
- 5xx/502: retry later; check hub.windmill.dev availability and backend logs for proxy errors
- 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
- Validate the project slug against the hub before running the import wizard
- Re-authenticate hub credentials before long import sessions
- Check instance egress to the hub when running behind restrictive firewalls
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
- ApiError with mapped HTTP status message (e.g. "Not Found",
- Generic Error: status: ${errorStatus}; status text: ${errorS
- Couldn't fetch resource types from hub ${hubBaseUrl}: ${(awa
- Couldn't fetch resource types from public hub:
- GET assets/graph -> ${res.status}: ${await res.text()}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/f4420cc409e18ebe.
Report an issue: GitHub.