denoland/deno · error · NodeError
ERR_STRING_TOO_LONG
ERR_STRING_TOO_LONG
Error message
Cannot create a string longer than 0x${maxStringLengthHex} characters What it means
Thrown by Deno's node:string_decoder polyfill when a single conversion would produce a string longer than V8's MAX_STRING_LENGTH (about 0x1fffffe8, roughly 536.8 million characters). bufferToString() computes the requested span (end - start, defaulting to the whole buffer) and refuses the conversion up front, because V8 cannot allocate a JS string that large. Node.js throws the same ERR_STRING_TOO_LONG guard when creating strings from oversized buffers.
Source
Thrown at ext/node/polyfills/string_decoder.ts:118
isTA
? TypedArrayPrototypeGetBuffer(buf)
: DataViewPrototypeGetBuffer(buf),
isTA
? TypedArrayPrototypeGetByteOffset(buf)
: DataViewPrototypeGetByteOffset(buf),
isTA
? TypedArrayPrototypeGetByteLength(buf)
: DataViewPrototypeGetByteLength(buf),
),
);
}
}
const maxStringLengthHex = NumberPrototypeToString(MAX_STRING_LENGTH, 16);
function bufferToString(buf, encoding, start, end) {
const len = (end ?? buf.length) - (start ?? 0);
if (len > MAX_STRING_LENGTH) {
throw new NodeError(
"ERR_STRING_TOO_LONG",
`Cannot create a string longer than 0x${maxStringLengthHex} characters`,
);
}
// deno-lint-ignore deno-internal/prefer-primordials -- buf is a Buffer; Buffer.prototype.toString(encoding) is not String.prototype.toString
return buf.toString(encoding, start, end);
}
const kBufferedBytes = Symbol("bufferedBytes");
const kMissingBytes = Symbol("missingBytes");
function decode(buf) {
const enc = this.enc;
let bufIdx = 0;
let bufEnd = buf.length;
let prepend = "";View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Decode incrementally: feed the StringDecoder fixed-size chunks (e.g. 1 MiB) with decoder.write() as data arrives, then decoder.end() at the end — partial multi-byte characters at chunk edges are buffered correctly
- Stream the source instead of buffering: for await (const chunk of fs.createReadStream(path)) text += decoder.write(chunk)
- If you already hold one huge buffer, loop over subarray(i, i + MAX) slices and decode each slice separately
- For base64/hex input, convert in chunks and avoid materializing the fully decoded output as one JS string at all
Example fix
// before
const text = new StringDecoder('utf8').end(fs.readFileSync('huge.bin'));
// after
const dec = new StringDecoder('utf8');
let text = '';
for await (const chunk of fs.createReadStream('huge.bin')) {
text += dec.write(chunk);
}
text += dec.end(); Defensive patterns
Strategy: validation
Validate before calling
// V8 max string length guard (matches MAX_STRING_LENGTH, ~2**29 - 24)
const MAX_STRING = 2 ** 29 - 24;
function decodeSafe(decoder, buf) {
if (buf.length <= MAX_STRING) {
return decoder.write(buf) + decoder.end();
}
let out = '';
for (let i = 0; i < buf.length; i += MAX_STRING) {
out += decoder.write(buf.subarray(i, i + MAX_STRING));
}
return out + decoder.end();
} Try / catch
try {
text = decoder.end(hugeBuf);
} catch (err) {
if (err?.code === 'ERR_STRING_TOO_LONG') {
// fall back to chunked decoding
text = decodeSafe(decoder, hugeBuf);
} else {
throw err;
}
} Prevention
- Never decode an unbounded buffer in one call — stream sources with fs.createReadStream and feed StringDecoder.write per chunk
- Cap accumulated buffer size before converting; treat ~512 MiB as the hard ceiling for a single JS string
- Remember encodings expand or shrink data (hex doubles size, base64 shrinks) — budget the decoded length, not the input length
- Prefer pipeline/stream APIs over readFileSync for any file whose size you do not control
When it happens
Trigger: Calling new StringDecoder(encoding).write(buf) or .end(buf) with a Buffer/TypedArray whose length (or end-start span) exceeds MAX_STRING_LENGTH: decoding a multi-hundred-MB file read with fs.readFileSync in one call, or accumulating network chunks into one giant buffer before decoding it as a single string.
Common situations: Reading whole large files (logs, dumps, media) into memory and decoding in one shot; merging streamed chunks into a single buffer before conversion; processing very large base64/hex payloads in one piece; test fixtures that accidentally reference huge binaries.
Related errors
- ERR_UNKNOWN_ENCODING
- ERR_UNKNOWN_ENCODING
- ERR_INVALID_ARG_VALUE
- TypeError [ERR_INVALID_OPT_VALUE_ENCODING]: The value "${enc
- ERR_INVALID_ARG_TYPE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/c0be4e2140f73df5.
Report an issue: GitHub.