clockworklabs/SpacetimeDB · error · RangeError

The encoding label provided is invalid

Error message

The encoding label provided is invalid

What it means

The SpacetimeDB V8 host installs its own TextEncoder/TextDecoder polyfill (crates/core/src/host/v8/builtins/text_encoding.js) that implements only UTF-8. Unlike the WHATWG Encoding Standard, which accepts dozens of labels and normalizes them, this polyfill compares the label as the exact string 'utf-8' and throws a RangeError for anything else.

Source

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

  encode(input = '') {
    return utf8_encode(input);
  }
};

globalThis.TextDecoder = class TextDecoder {
  /** @type {string} */
  #encoding;

  /** @type {boolean} */
  #fatal;

  /**
   * @argument {string} label
   * @argument {any} options
   */
  constructor(label = 'utf-8', options = {}) {
    if (label !== 'utf-8') {
      throw new RangeError('The encoding label provided is invalid');
    }
    this.#encoding = label;
    this.#fatal = !!options.fatal;
    if (options.ignoreBOM) {
      throw new TypeError("Option 'ignoreBOM' not supported");
    }
  }

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

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Pass no label at all — the constructor defaults to 'utf-8': new TextDecoder()
  2. Normalize labels before constructing: lowercase and ensure the dash form 'utf-8'
  3. For non-UTF-8 data, transcode it to UTF-8 on the client/broker side before it reaches the module

Example fix

// before
const dec = new TextDecoder(label); // RangeError unless label === 'utf-8'

// after
const dec = new TextDecoder(label === 'utf8' || label === 'UTF-8' ? 'utf-8' : label);
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = 'utf-8';
function normalizeLabel(label?: string): string {
  const norm = (label ?? 'utf-8').trim().toLowerCase().replace(/^utf8$/, 'utf-8');
  if (norm !== SUPPORTED) {
    throw new RangeError(`Encoding '${label}' is not supported; only utf-8 is. Transcode the data first.`);
  }
  return norm;
}
const dec = new TextDecoder(normalizeLabel(userLabel));

Type guard

function isSupportedEncodingLabel(label: string): boolean {
  return label.trim().toLowerCase() === 'utf-8' || label.trim().toLowerCase() === 'utf8';
}

Try / catch

try {
  const dec = new TextDecoder(label);
} catch (e) {
  if (e instanceof RangeError && /encoding label/.test(e.message)) {
    // fall back to utf-8 only if the payload is known to be UTF-8
    return new TextDecoder();
  }
  throw e;
}

Prevention

When it happens

Trigger: Constructing new TextDecoder('utf-16le'), new TextDecoder('windows-1252'), or any non-'utf-8' label; also labels browsers would normalize, such as 'utf8' (no dash), 'UTF-8' (uppercase), or 'unicode-1-1-utf-8', because the raw string is compared.

Common situations: Decoding payloads encoded with a legacy charset; porting browser or Node code that passes a shorthand label like 'utf8'; receiving data from systems that emit UTF-16 and trying to decode it in-module.

Related errors


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