Budibase/budibase · error · Error

Failed to fetch file from URL: ${fallbackResponse.statusText

Error message

Failed to fetch file from URL: ${fallbackResponse.statusText}

What it means

After an attempt to pass the file to the LLM via upload fails, processUrlFile falls back to inlining: it re-fetches the file URL itself and, if that fallback fetch is not OK, throws with the fallback response's statusText. This is the same download failure as the primary path but reached via the upload-failure fallback branch.

Source

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

    return { kind: "image", value: toImageDataUrl(data, fileType) }
  }

  const filename = `document.${fileType || "pdf"}`
  try {
    const uploaded = await llm.uploadFile(
      response.body as Readable,
      filename,
      fileType
    )
    return {
      kind: "file",
      value: uploaded,
    }
  } catch (error) {
    if (shouldInlineFileAfterUploadFailure(error)) {
      const fallbackResponse = await fetchWithBlacklist(fileUrl)
      if (!fallbackResponse.ok) {
        throw new Error(
          `Failed to fetch file from URL: ${fallbackResponse.statusText}`
        )
      }
      const data = await fallbackResponse.buffer()
      const text = await extractPdfText(data)
      return { kind: "text", value: text }
    }
    throw error
  }
}

async function processAttachmentFile(
  attachment: any,
  llm: LLMResponse
): Promise<ExtractInput> {
  const bucket = objectStore.ObjectStoreBuckets.APPS
  const { stream } = await objectStore.getReadStream(bucket, attachment.key!)
  const contentType = attachment.extension

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Confirm the file URL returns 200 with curl and replace it with a working URL
  2. Re-upload the file to accessible storage and update the step's fileUrl
  3. If the upload failure is persistent, check LLM provider status/quota so the fallback isn't needed
  4. Retry the automation if the upstream outage was transient

Example fix

// before
fileUrl: "https://example.com/tmp/report.pdf" // signed URL expired → 403
// after
fileUrl: "https://example.com/permanent/report.pdf" // 200
Defensive patterns

Strategy: fallback

Validate before calling

const check = await fetchWithBlacklist(fileUrl)
if (!check.ok) throw new Error(`Source URL dead before run: ${check.status}`)

Try / catch

try {
  const input = await processUrlFile(params, fileUrl, fileType, llm)
} catch (err) {
  if (err.message.startsWith("Failed to fetch file from URL:")) {
    // both upload and inline fallback failed; surface URL as unusable
  }
  throw err
}

Prevention

When it happens

Trigger: shouldInlineFileAfterUploadFailure(error) is true (LLM upload failed) and the subsequent fetchWithBlacklist(fileUrl) returns non-OK (404/403/5xx), so the inline-text fallback cannot download the file either.

Common situations: LLM upload fails AND the source URL has expired or returns errors; transient upstream outages hit both the upload and the direct fetch; rate-limited or IP-blocked asset host.

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/3589989349cb13ae. Report an issue: GitHub.