Budibase/budibase · error · HTTPError

Failed to fetch import data (status ${response.status})

Error message

Failed to fetch import data (status ${response.status})

What it means

fetchFromUrl downloads REST import data (an OpenAPI spec or curl command) from a user-supplied URL. When the HTTP response has a non-2xx status (response.ok is false), it throws an HTTPError carrying the upstream status code. This distinguishes 'the server answered but refused the request' from transport-level failures.

Source

Thrown at packages/server/src/api/controllers/query/import/index.ts:103

  if (parsed.username || parsed.password) {
    throw new HTTPError("Import url must not contain credentials", 400)
  }

  return parsed
}

async function fetchFromUrl(url: string): Promise<string> {
  try {
    // validate protocol / credentials up front for clear 400 errors
    parseImportUrl(url)
    // fetchWithBlacklist resolves and validates the target, pins the request to
    // the validated IP (preventing DNS rebinding between validation and the
    // actual connection) and safely follows redirects, re-validating each hop.
    const response = await utils.fetchWithBlacklist(url)

    if (!response.ok) {
      throw new HTTPError(
        `Failed to fetch import data (status ${response.status})`,
        response.status
      )
    }

    return await response.text()
  } catch (error: any) {
    if (error instanceof HTTPError) {
      throw error
    }
    const message = error?.message || "Unknown error"
    throw new HTTPError(`Failed to fetch import data - ${message}`, 502)
  }
}

export async function getImportInfo(
  input: { data: string } | { url: string }
): Promise<ImportInfo> {

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Open the URL directly in a browser/curl to confirm what status it returns and fix the hosting/auth on the source side
  2. If the spec needs authentication, download it manually and paste the contents as `data` instead of `url`
  3. Retry later if the status is 429/5xx, as the upstream may be temporarily unavailable
  4. Verify the URL points at the raw spec file, not an HTML viewer page (e.g. Swagger UI)

Example fix

// before
await createImporter({ url: "https://petstore.example.com/swagger/ui" }) // 404
// after
await createImporter({ url: "https://petstore.example.com/v2/swagger.json" })
Defensive patterns

Strategy: try-catch

Validate before calling

const res = await fetch(url, { method: "HEAD" })
if (!res.ok) throw new Error(`Spec URL returned ${res.status} before import`)

Type guard

null

Try / catch

try {
  await createImporter({ url })
} catch (e) {
  if (e instanceof HTTPError && e.status === 404) {
    // spec missing: ask user to re-host or paste the spec
  } else if (e instanceof HTTPError && [429, 500, 502, 503].includes(e.status)) {
    // retryable upstream error
  }
  throw e
}

Prevention

When it happens

Trigger: Calling createImporter/getImportInfo with { url } where the remote host returns 404 (spec moved/renamed), 401/403 (spec requires auth), 500 (server error), or any other non-2xx status.

Common situations: Importing a Swagger URL that now redirects to a login page; a spec hosted behind a private repo that returns 404; a rate-limited API gateway returning 429; a self-hosted spec server that is misconfigured and returns 5xx.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/d83cd264a38b9ac8. Report an issue: GitHub.