Skip to content

A ReadableStream branch was created but never consumed #648

@HaidongPang

Description

@HaidongPang

I'm using ky in cloudflare worker with following code:

import ky from "ky";
export default {
    async fetch (): Promise<Response> {
        const result = await ky.get("https://www.github.com").text();
        return new Response(result);
    }
} satisfies ExportedHandler;

and when I turn off local mode, requests raise the following warning:

A ReadableStream branch was created but never consumed. Such branches can be created, for instance, by calling the tee() method on a ReadableStream, or by calling the clone() method on a Request or Response object. If a branch is created but never consumed, it can force the runtime to buffer the entire body of the stream in memory, which may cause the Worker to exceed its memory limit and be terminated. To avoid this, ensure that all branches created are consumed.

 * Unused stream created:
    at result.<computed> [as text] (file:///....../node_modules/ky/source/core/Ky.ts:92:36)
......

Locate the following code snippet:

source/core/Ky.ts

export class Ky {
	static create(input: Input, options: Options): ResponsePromise {
		const ky = new Ky(input, options);

		const function_ = async (): Promise<Response> => {
                         ......
		};

		......

		for (const [type, mimeType] of Object.entries(responseTypes) as ObjectEntries<typeof responseTypes>) {
			result[type] = async () => {
				......
				const awaitedResult = await result;
				const response = awaitedResult.clone();

				if (type === 'json') {
					if (response.status === 204) {
						return '';
					}

					const arrayBuffer = await response.clone().arrayBuffer();
					const responseSize = arrayBuffer.byteLength;
					if (responseSize === 0) {
						return '';
					}

					if (options.parseJson) {
						return options.parseJson(await response.text());
					}
				}

				return response[type]();
			};
		}

		return result;
	}

The awaitedResult is a variable of type Response. Since it is declared, it has been cloned only once, and its ReadableStream has never been consumed.
After awaitedResult has finished cloning, its ReadableStream should be closed to ensure memory safety.
Seems like:

const awaitedResult = await result;
const response = awaitedResult.clone();
await awaitedResult.body.cancel();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions