Skip to content

fix: consume stream response body via streamToString instead of res.response.text() - #10810

Merged
joehan merged 6 commits into
mainfrom
fix-fetch-body-consumption
Jul 24, 2026
Merged

fix: consume stream response body via streamToString instead of res.response.text()#10810
joehan merged 6 commits into
mainfrom
fix-fetch-body-consumption

Conversation

@joehan

@joehan joehan commented Jul 17, 2026

Copy link
Copy Markdown
Member

Fixes #10809

Root Cause

When native fetch is used with responseType: "stream", apiv2.ts converts the Fetch API's ReadableStream (res.body) into a Node.js Readable stream using Readable.fromWeb(res.body). Under Web Streams API semantics, this locks the underlying ReadableStream. Subsequent calls to res.response.text() on the native Response object throw TypeError: Body is unusable: Body has already been read.

Fix

Updated handlers that consume stream responses to read from res.body via streamToString(res.body) rather than calling res.response.text().

Verification

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces direct calls to .text() on response objects with streamToString to read response bodies as streams across several files, and adds corresponding error-handling tests. The review feedback correctly points out that the response body can be null or undefined, which would lead to runtime TypeErrors when passed to streamToString. To adhere to the repository's strict null checks style guide, you should explicitly handle these nullish cases before attempting to read the stream.

Comment thread src/commands/database-get.ts
Comment thread src/deploy/hosting/uploader.ts Outdated
Comment thread src/emulator/hubExport.ts Outdated
Comment thread src/init/features/database.ts
Comment thread src/mcp/tools/core/get_security_rules.ts
Comment thread src/profiler.ts
@joehan
joehan requested a review from aalej July 17, 2026 19:30
Comment thread src/emulator/hubExport.ts Outdated
});
if (res.status >= 400) {
throw new FirebaseError(`Failed to export storage: ${await res.response.text()}`);
const errorMsg = res.body ? await streamToString(res.body as NodeJS.ReadableStream) : "";

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of casting, please set the generic type on client.request (as we do already in profiler.ts)

Comment thread src/deploy/hosting/uploader.ts Outdated
}
if (res.status !== 200) {
const errorMessage = await res.response.text();
const errorMessage = res.body ? await streamToString(res.body as NodeJS.ReadableStream) : "";

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of casting, please set the generic type on client.request (as we do already in profiler.ts)

@joehan
joehan requested a review from bkendall July 24, 2026 17:11
Comment thread src/commands/database-get.ts Outdated
if (res.status >= 400) {
// TODO(bkendall): consider moving stream-handling logic to responseToError.
const r = await res.response.text();
const r = res.body ? await utils.streamToString(res.body) : "";

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needing to do this at the call site is ugly. Let's move it into the util.streamtoString function

@joehan
joehan merged commit ebaf483 into main Jul 24, 2026
52 of 53 checks passed
@joehan
joehan deleted the fix-fetch-body-consumption branch July 24, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hosting: upload HTTP errors are masked by "Body is unusable" after stream response wrapping

3 participants