Budibase/budibase · error · Error
Failed to download asset: ${response.statusText}
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.
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)
Solutions
- Verify the asset URL is publicly reachable (curl it) and returns 200
- Re-upload or regenerate the asset / signed URL if it expired or was deleted
- Ensure the URL requires no auth headers that plain fetch does not send
- 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
- Use stable, publicly reachable URLs for assets
- Regenerate signed URLs before long-running automations
- Check response.ok yourself and retry transient 5xx with backoff
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
- Failed to fetch file from URL: ${response.statusText}
- Failed to fetch file from URL: ${fallbackResponse.statusText
- Unexpected response when fetching openid-configuration: ${re
- unexpected response ${response.statusText}
- Unexpected response ${response.statusText}
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/4eb17e799507ece5.
Report an issue: GitHub.