denoland/deno · error · TypeError
brotli compression failed
Error message
brotli compression failed
What it means
Deno's Web Streams CompressionStream implementation for the 'brotli' format: each write/flush runs through BrotliEncoderCompressStream, and if the native encoder returns failure (ok == false), the stream errors with ErrorKind::InvalidData and this message. Encoder failures are rare and usually indicate invalid stream state or memory pressure rather than bad input data.
Source
Thrown at ext/web/compression.rs:107
let mut output_offset = 0;
let mut total_out = Some(0);
loop {
let mut available_out = output.len() - output_offset;
let ok = self.stm.compress_stream(
operation,
&mut available_in,
input,
&mut input_offset,
&mut available_out,
&mut output,
&mut output_offset,
&mut total_out,
&mut |_, _, _, _| (),
);
if !ok {
return Err(CompressionError::IoTypeError(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"brotli compression failed",
)));
}
let done = match operation {
BrotliEncoderOperation::BROTLI_OPERATION_FINISH => {
self.stm.is_finished()
}
_ => available_in == 0 && !self.stm.has_more_output(),
};
if done {
output.truncate(output_offset);
return Ok(output);
}
if output_offset == output.len() {View on GitHub (pinned to a961cdec3b)
Solutions
- Confirm the format is exactly 'brotli' (not 'br', 'gzip', 'deflate', or 'deflate-raw').
- Stream in modest chunks via pipeThrough(new CompressionStream('brotli')) instead of one huge write(), letting backpressure work.
- Catch the stream error and fall back to identity or gzip/deflate compression so the response still ships.
- Update Deno — native encoder fixes land in runtime updates.
Example fix
// before
const out = await new Response(blob.pipeThrough(new CompressionStream("brotli")).catch(() => blob)).arrayBuffer(); // unhandled mid-stream error
// after
async function compressBrotli(blob) {
try {
return { body: blob.pipeThrough(new CompressionStream("brotli")), encoding: "br" };
} catch {
return { body: blob, encoding: "identity" }; // graceful fallback
}
} Defensive patterns
Strategy: fallback
Validate before calling
const VALID = new Set(["gzip", "deflate", "deflate-raw", "brotli"]);
if (!VALID.has(format)) throw new Error(`CompressionStream format must be one of ${[...VALID]}, got ${format}`); Try / catch
try { return await compressWith(new CompressionStream("brotli"), bytes); } catch (e) { if (/brotli compression failed/.test(String(e))) return bytes; /* identity fallback */ throw e; } Prevention
- Use pipeThrough with backpressure instead of single giant write() calls.
- Keep runtime updated — native brotli encoder fixes ship with Deno releases.
- Always ship an identity/gzip fallback path when compression is best-effort.
When it happens
Trigger: new CompressionStream('brotli') whose writer hits a native encoder failure during write(), flush(), or close() — e.g. corrupted encoder state after misuse of the stream, extremely large single-shot buffers, or a native brotli bug triggered by specific chunk boundaries.
Common situations: Server-side response compression pipelines built on CompressionStream('brotli'); piping very large files through a single write; version-specific encoder regressions; feeding the wrong format string ('br' instead of 'brotli' throws earlier, but near-misses confuse debugging).
Related errors
- brotli decompression failed
- Invalid header: length must be 2, but is ${header.length}
- Invalid header name: "${name}"
- Cannot change header: headers are immutable
- ERR_INVALID_ARG_TYPE
AI-assisted analysis of denoland/deno@a961cdec3b (2026-08-20).
Data as JSON: /api/errors/2c678ad41d8af6ec.
Report an issue: GitHub.