Budibase/budibase · error
Unexpected response body stream type
Error message
Unexpected response body stream type
What it means
processUrlAttachment requires the fetch response body to be a Node stream.Readable so it can stream content into the object store. If body exists but is not a Readable (e.g. it's a web ReadableStream/Blob from a non-Node fetch implementation), the library throws this type-mismatch error.
Source
Thrown at packages/backend-core/src/objectStore/utils.ts:80
return {
Bucket: bucketName,
LifecycleConfiguration: lifecycleConfiguration,
}
}
async function processUrlAttachment(
attachment: AutomationAttachment
): Promise<AutomationAttachmentContent> {
const response = await fetchWithBlacklist(attachment.url)
if (!response.ok || !response.body) {
throw new Error(`Unexpected response ${response.statusText}`)
}
const fallbackFilename = path.basename(new URL(attachment.url).pathname)
if (!response.body) {
throw new Error("No response received for attachment")
}
if (!(response.body instanceof stream.Readable)) {
throw new Error("Unexpected response body stream type")
}
return {
filename: attachment.filename || fallbackFilename,
content: response.body,
}
}
export async function processObjectStoreAttachment(
attachment: AutomationAttachment
): Promise<BucketedContent> {
const result = objectStore.extractBucketAndPath(attachment.url)
if (result === null) {
throw new Error("Invalid signed URL")
}
const { bucket, path: objectPath } = result
const { stream: readStream } = await objectStore.getReadStream(View on GitHub (pinned to a81a902e9a)
Solutions
- Use the Node 18+ built-in fetch (undici is already nodeified) and avoid polyfills that don't return node streams
- If using a custom fetch, wrap the body: stream.Readable.fromWeb(body) before returning the response
- In tests, stub responses with stream.Readable instances (e.g. stream.Readable.from([buffer]))
- Pin/verify the version of any global fetch overriding packages
Example fix
// before
const response = { ok: true, body: await res.arrayBuffer() }
// after
const response = { ok: true, body: stream.Readable.fromWeb(res.body) } Defensive patterns
Strategy: type-guard
Validate before calling
const res = await fetch(url)
if (!(res.body instanceof (await import("stream")).Readable)) throw new Error("Body is not a node stream") Type guard
function isReadable(b: unknown): b is import("stream").Readable {
return b instanceof (await import("stream")).Readable
} Try / catch
try {
const content = await processUrlAttachment(attachment)
} catch (err) {
if (err.message === "Unexpected response body stream type") {
// fetch implementation returns web streams: fix polyfill or convert
}
throw err
} Prevention
- Do not replace global fetch with non-nodeifying polyfills
- Convert web ReadableStreams with stream.Readable.fromWeb before passing
- In tests, stub bodies with stream.Readable instances
- Keep Node version (per .nvmrc) so built-in fetch returns Node streams
When it happens
Trigger: The fetch implementation used by fetchWithBlacklist returns a web-standard ReadableStream instead of a Node stream.Readable — typically from a runtime mismatch, an injected fetch polyfill, or a mocked fetch in custom setups.
Common situations: Custom undici/nodeify patches of global fetch, running inside environments where fetch returns WHATWG streams, or tests stubbing fetch with objects whose body is not a Readable.
Related errors
- Unexpected response ${response.statusText}
- No response received for attachment
- Invalid signed URL
- Automation trigger is not an email trigger
- Attachments must have both "url" and "filename" keys. You ha
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/260bb1862335f912.
Report an issue: GitHub.