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

  1. Use the Node 18+ built-in fetch (undici is already nodeified) and avoid polyfills that don't return node streams
  2. If using a custom fetch, wrap the body: stream.Readable.fromWeb(body) before returning the response
  3. In tests, stub responses with stream.Readable instances (e.g. stream.Readable.from([buffer]))
  4. 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

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


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