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
- Pass no label at all — the constructor defaults to 'utf-8': new TextDecoder()
- Normalize labels before constructing: lowercase and ensure the dash form 'utf-8'
- 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
- Omit the label argument unless you truly need to vary encodings
- Enforce UTF-8 at every boundary (clients, brokers) so modules never see other encodings
- Centralize decoder construction in one helper so the label constraint is checked in one place
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
- Option 'ignoreBOM' not supported
- Option 'stream' not supported
- Math.random is not available in SpacetimeDB modules. Use ctx
- must export schema as default export
- default export is not a Schema object
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/59ff33436c4106df.
Report an issue: GitHub.