Budibase/budibase · error · HTTPError

Failed to fetch import data - ${message}

Error message

Failed to fetch import data - ${message}

What it means

This is the catch-all wrapper in fetchFromUrl: any non-HTTPError failure during the URL fetch (DNS failure, connection refused, timeout, TLS error, or invalid URL rejected by parseImportUrl... though that path rethrows as HTTPError) is converted into an HTTPError with status 502 and the underlying error message appended. It tells you the fetch itself blew up rather than returning a bad status.

Source

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

    // 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> {
  const importer = await createImporter(input)
  return importer.getInfo()
}

async function urlToSpecs(url: string, cacheKeyBase?: string): Promise<string> {
  if (!cacheKeyBase) {
    const result = await fetchFromUrl(url)
    return result
  }

  const cacheKey = `${cacheKeyBase}:specs`
  const client = await redis.clients.getOpenapiImportSpecsClient()

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Read the appended message (e.g. ENOTFOUND, ECONNREFUSED, self signed certificate) to identify the transport failure
  2. Verify the hostname resolves and the port is reachable from the Budibase server, not just your machine
  3. If the spec is internal, host it on an address the server can access or paste the spec content as `data`
  4. Fix TLS issues by using a properly signed certificate (or importing your CA into the Node trust store)

Example fix

// before
await createImporter({ url: "http://internal-spec.local/openapi.yaml" }) // ENOTFOUND
// after
await createImporter({ data: fs.readFileSync("openapi.yaml", "utf8") })
Defensive patterns

Strategy: try-catch

Validate before calling

const parsed = new URL(url)
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("Only HTTP(S) URLs allowed")
await dns.promises.lookup(parsed.hostname) // must resolve from the server host

Type guard

null

Try / catch

try {
  await createImporter({ url })
} catch (e) {
  const msg = String(e?.message ?? "")
  if (msg.includes("ENOTFOUND") || msg.includes("ECONNREFUSED")) {
    // network/DNS problem: fix host or run where reachable
  } else if (msg.includes("certificate")) {
    // TLS problem: install CA or use https with valid cert
  }
  throw e
}

Prevention

When it happens

Trigger: fetchWithBlacklist throws because the host cannot be resolved (ENOTFOUND), the connection is refused (ECONNREFUSED), the TLS handshake fails, a redirect leads to a blocked/blacklisted IP, or the request times out.

Common situations: Importing from a URL in an air-gapped/private network the server cannot reach; typos in the hostname (e.g. http://localhsot); self-signed certificates; SSRF protection rejecting a redirect to an internal address.

Related errors


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