clockworklabs/SpacetimeDB · error · TypeError

Option 'stream' not supported

Error message

Option 'stream' not supported

What it means

The TextDecoder polyfill in the SpacetimeDB V8 host has no streaming decode state: decode(input, options) throws TypeError('Option stream not supported') whenever options.stream is truthy. Each decode() call is independent, so incremental decoding must be done by the caller.

Source

Thrown at crates/core/src/host/v8/builtins/text_encoding.js:57

  }

  get encoding() {
    return this.#encoding;
  }
  get fatal() {
    return this.#fatal;
  }
  get ignoreBOM() {
    return false;
  }

  /**
   * @argument {any} input
   * @argument {any} options
   */
  decode(input, options = {}) {
    if (options.stream) {
      throw new TypeError("Option 'stream' not supported");
    }
    if (input instanceof ArrayBuffer || input instanceof SharedArrayBuffer) {
      input = new Uint8Array(input);
    }
    return utf8_decode(input, this.#fatal);
  }
};

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Accumulate chunks in a buffer and call decode() once, without options, when the message is complete
  2. If every chunk is message-complete and ends on a UTF-8 codepoint boundary (true for frames you framed yourself), call decode(chunk) with no options
  3. Move incremental decoding of untrusted/boundary-split streams outside the module

Example fix

// before
for (const chunk of chunks) parts.push(dec.decode(chunk, { stream: true }));

// after
let buf = new Uint8Array(0);
for (const chunk of chunks) {
  const merged = new Uint8Array(buf.length + chunk.length);
  merged.set(buf); merged.set(chunk, buf.length);
  buf = merged;
}
const text = dec.decode(buf);
Defensive patterns

Strategy: validation

Validate before calling

function decodeAll(dec: TextDecoder, chunks: Uint8Array[]): string {
  if (chunks.length === 1) return dec.decode(chunks[0]);
  const total = chunks.reduce((n, c) => n + c.length, 0);
  const buf = new Uint8Array(total);
  let off = 0;
  for (const c of chunks) { buf.set(c, off); off += c.length; }
  return dec.decode(buf); // no options: stream is unsupported
}

Type guard

function isStreamSafe(chunks: Uint8Array[]): boolean {
  // Safe only if each chunk is a complete message; conservative default: false
  return chunks.length <= 1;
}

Try / catch

try {
  text = dec.decode(chunk, options);
} catch (e) {
  if (e instanceof TypeError && /stream/.test(e.message)) {
    pending.push(chunk); // buffer and decode once complete
  } else throw e;
}

Prevention

When it happens

Trigger: Calling decoder.decode(chunk, { stream: true }) while feeding chunked data (websocket frames, file reads, socket streams) into the decoder.

Common situations: Porting streaming parsers from browsers/Node that rely on BOM/state carry-over between decode calls; handling large payloads split across messages.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/fa559caf1fd8609e. Report an issue: GitHub.