← textStream() for response/request/blob

v151 · fileapi · member reference

Blob.textStream()

Reads a Blob (or File) as a ReadableStream of UTF-8-decoded strings — the streaming counterpart of blob.text(), defined in W3C FileAPI. Unlike the Body-mixin version, every call creates a fresh stream.

Syntax

// W3C FileAPI — Blob (normative IDL)
ReadableStream textStream();

// Call form
const stream = blob.textStream();

Chromium's binding: [RuntimeEnabled=TextStreamMethod, CallWith=ScriptState, NewObject, RaisesException] ReadableStream textStream(); in blob.idl.

Source: FileAPI — Blob.textStream(); Chromium blob.idl

Inputs

The method takes no parameters. Its only input is the blob's own byte sequence. Notably there is no encoding argument: FileAPI points out this differs from FileReader.readAsText(), which accepts an encoding label — textStream() always decodes UTF-8.

Source: FileAPI — Blob.textStream() steps and note

Outputs

Returns a ReadableStream whose chunks are strings: the result of the blob's get stream algorithm (a new ReadableStream created in the blob's relevant realm) piped through a TextDecoderStream set up with UTF-8.

An empty blob therefore yields an already-empty stream (no chunks), not an error.

Source: FileAPI — Blob.textStream() steps; FileAPI — Blob get stream algorithm

Errors

No synchronous exceptions in the spec steps: unlike the Body-mixin version, FileAPI's textStream() steps define no throw paths — a blob can always produce a fresh stream. (Chromium's binding still carries RaisesException; treat that as an implementation detail, not a spec contract.)

Asynchronous stream failures: a File-backed blob can fail while being read. FileAPI defines exactly five failure reasonsNotFound, UnsafeFile, TooManyReads, SnapshotState, and FileLock — and a read that fails for one of these reasons errors the stream with that failure reason: pending and future read() promises reject. Handle rejection from the reader, not a try/catch around the call.

Not to be confused with FileReader errors: the NotFoundError-style DOMException names are FileAPI's mapping for the FileReader read methods (thrown by synchronous reads or surfaced via FileReader.error for asynchronous ones). A ReadableStream from textStream() is errored with the raw failure reason itself — do not test for DOMException names here.

Malformed bytes: as with the Body version, decoding is non-fatal by default (TextDecoderOptions.fatal defaults to false), so invalid UTF-8 yields U+FFFD replacement characters rather than an error.

Source: FileAPI — Blob.textStream() steps; FileAPI — failure reason; Encoding Standard — TextDecoderOptions / error mode

Context

Receiver: any Blob, including File objects from file pickers (<input type="file">), drag-and-drop, the clipboard, or constructed blobs.

Exposure: Blob is exposed in both Window and Worker contexts (Chromium's blob.idl; the WPT suite is an .any.js running in window and worker). No secure-context requirement and no permission prompt for same-page blobs.

Availability: Chrome 151 per the milestone listing and BCD; gated at build time by the TextStreamMethod runtime feature (status stable at trunk).

Source: Chromium blob.idl; WPT Blob-textStream.any.js; Chromium runtime_enabled_features.json5; chromestatus.com/feature/5146752165478400

Lifecycle

Repeatable, unlike Body: every call runs the blob's get stream algorithm, which creates a new ReadableStream. There is no bodyUsed and no “unusable” state — you may call textStream() many times, even concurrently, and each stream is independent.

Underlying mutability: a Blob's bytes are immutable for the page, but a File on disk can change or disappear between call and completion — that is exactly when the asynchronous failure reason path errors the stream (see Errors).

Stream lifetime: each returned stream follows ordinary pipe semantics (locked while read, closed at end).

Source: FileAPI — Blob get stream algorithm; FileAPI — failure reason

Examples

// Stream a user-picked file as decoded text chunks.
// (input is an <input type="file"> element)
const file = input.files[0];
const reader = file.textStream().getReader();

try {
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    process(value); // value is a string, UTF-8 decoded
  }
} catch (err) {
  // Asynchronous read failure — e.g. the file changed on disk
  // (FileAPI failure reason), not a malformed-bytes error.
  console.error("read failed:", err);
}
Source: WPT Blob-textStream.any.js; FileAPI — Blob.textStream()

Compatibility

Blob.textStream() — from BCD api/Blob.json (checked 2026-07-26)
Engine / runtimeSupportNotes
Chrome151Matches the Chrome 151 milestone listing (Enabled by default); Chrome for Android and WebView (Android + iOS) are BCD mirrors
EdgemirrorBCD mirrors Chrome's data
FirefoxNot supportedBCD version_added: false (Firefox for Android mirrors); vendor signal recorded on the ChromeStatus entry: No signal
SafariNot supportedBCD version_added: false (Safari on iOS mirrors); the ChromeStatus entry records a Positive signal — a recorded signal, not an official WebKit standards position (a feature this small has none)
Node.js26.5.0BCD records version_added: 26.5.0
DenoUnknownNo BCD entry as of 2026-07-26

Support rows are from BCD only. Separately, vendor signals come from the ChromeStatus API feature record (checked 2026-07-26): Firefox “No signal”, Safari “Positive”, web developers “No signals”. No Baseline entry: the webstatus.dev query returns no feature (checked 2026-07-26).

Source: BCD api/Blob.json; ChromeStatus API feature record; webstatus.dev query

Security and privacy

No new authority: the method needs no permission or gesture beyond whatever produced the blob (a file picker's user selection, a constructed blob, drag-and-drop). It only reads bytes the page already holds.

Deterministic decoding: always UTF-8 — unlike readAsText(), no encoding label can be supplied or inherited, so the decoding contract cannot be renegotiated per blob; malformed bytes become U+FFFD replacement text rather than an exception channel.

Disclosure/storage: reading is local; nothing is transmitted or persisted by this method, and stream lifetime is bounded by the blob's own lifetime. File-backed reads can fail asynchronously if the underlying file changes — surface that failure to the user rather than silently truncating.

Source: FileAPI — Blob.textStream() steps and note; FileAPI — failure reason