Budibase/budibase · error · Error

Failed to download asset

Error message

Failed to download asset: ${response.statusText}

What it means

downloadAssetsForExtract fetches model-unsupported URLs manually (when the LLM cannot download the asset itself) using plain fetch. Any non-OK HTTP status causes it to throw with the response's statusText, aborting the extract step's asset preparation.

Solutions

  1. Verify the asset URL is publicly reachable (curl it) and returns 200
  2. Re-upload or regenerate the asset / signed URL if it expired or was deleted
  3. Ensure the URL requires no auth headers that plain fetch does not send
  4. Check the asset server/CDN logs for the failing status

Example fix

// before
const response = await fetch(expiredSignedUrl) // 403 Forbidden
// after
const freshUrl = await regenerateSignedUrl(assetId)
const response = await fetch(freshUrl) // 200 OK
Defensive patterns

Strategy: retry

Validate before calling

const head = await fetch(url, { method: "HEAD" })
if (!head.ok) throw new Error(`Asset URL unreachable: ${head.status}`)

Try / catch

try {
  await downloadAssetsForExtract(url, isUrlSupportedByModel)
} catch (err) {
  if (err.message.startsWith("Failed to download asset:")) {
    // retry with backoff or refresh the asset URL
  }
  throw err
}

Prevention

When it happens

Trigger: fetch(url) in downloadAssetsForExtract returns response.ok === false — e.g. 404 (asset moved/deleted), 403 (private/permission-denied URL), 500 from the asset server — for a URL the model cannot ingest directly.

Common situations: Attachment/upload URLs that expired (signed URLs past expiry); assets behind authentication; public URLs that later 404; CDN or storage (S3/MinIO) misconfiguration returning errors.

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 Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/4eb17e799507ece5. Report an issue: GitHub.

Appendix: source

Thrown at packages/server/src/automations/steps/ai/extract.ts:91

    "The data array must contain at most 1 object.",
    "Do not include markdown, explanations, or extra keys.",
    'If no matching data is found, return {"data": []}.',
  ].join("\n\n")
}

const downloadAssetsForExtract: Experimental_DownloadFunction =
  async requests =>
    Promise.all(
      requests.map(async ({ url, isUrlSupportedByModel }) => {
        if (url.protocol === "data:") {
          return null
        }
        if (isUrlSupportedByModel) {
          return null
        }
        const response = await fetch(url)
        if (!response.ok) {
          throw new Error(`Failed to download asset: ${response.statusText}`)
        }
        return {
          data: new Uint8Array(await response.arrayBuffer()),
          mediaType: response.headers.get("content-type") ?? undefined,
        }
      })
    )

function buildExtractModelMessages(input: ExtractInput): ModelMessage[] {
  const prompt = buildExtractPrompt()
  const userContent: UserContent =
    input.kind === "image"
      ? [
          {
            type: "image",
            image: new URL(input.value),
          },
          {

View on GitHub (pinned to a81a902e9a)