{"record":{"id":"5110631b803c743d","repo":"denoland/deno","slug":"brotli-decompression-failed","errorCode":null,"errorMessage":"brotli decompression failed","messagePattern":"brotli decompression failed","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/compression.rs","lineNumber":289,"sourceCode":"    .take()\n    .ok_or(CompressionError::ResourceClosed)?;\n  let out = match inner {\n    Inner::DeflateDecoder(d) => {\n      d.finish().map_err(CompressionError::IoTypeError)\n    }\n    Inner::DeflateEncoder(d) => {\n      d.finish().map_err(CompressionError::IoTypeError)\n    }\n    Inner::DeflateRawDecoder(d) => {\n      d.finish().map_err(CompressionError::IoTypeError)\n    }\n    Inner::DeflateRawEncoder(d) => {\n      d.finish().map_err(CompressionError::IoTypeError)\n    }\n    Inner::GzDecoder(d) => d.finish().map_err(CompressionError::IoTypeError),\n    Inner::GzEncoder(d) => d.finish().map_err(CompressionError::IoTypeError),\n    Inner::BrotliDecoder(d) => d.into_inner().map_err(|_| {\n      CompressionError::IoTypeError(std::io::Error::new(\n        std::io::ErrorKind::InvalidData,\n        \"brotli decompression failed\",\n      ))\n    }),\n    Inner::BrotliEncoder(d) => d.finish(),\n  };\n  match out {\n    Err(err) => {\n      if report_errors {\n        Err(err)\n      } else {\n        Ok(Vec::with_capacity(0).into())\n      }\n    }\n    Ok(out) => Ok(out.into()),\n  }\n}\n","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/denoland/deno/blob/a961cdec3b1948844414ebeecc697dcad76df2d1/ext/web/compression.rs#L271-L307","documentation":"Deno's DecompressionStream for 'brotli': when the stream finishes (writer closed), the underlying brotli decoder is finalized via into_inner(); if the compressed data ended mid-stream (incomplete brotli stream) or is corrupt, finalization fails and the stream errors with ErrorKind::InvalidData. Note the wrapper suppresses errors when report_errors is false, in which case the symptom is a silently empty/truncated result instead of this error.","triggerScenarios":"Piping truncated or corrupt brotli data through DecompressionStream('brotli') and then closing the writer: cut-off downloads, files truncated by disk limits, or upstream errors where Content-Length promised more bytes than the compressed stream contained.","commonSituations":"Decompressing .br assets whose download was interrupted; proxy-truncated responses; concatenating or hand-editing brotli files; precompressed artifacts produced by a different/older brotli version.","solutions":["Verify the source integrity before decompressing (Content-Length match, checksum/hash of the .br payload).","Re-download or regenerate the brotli artifact from a trusted source.","Catch the stream error explicitly and report which asset failed instead of propagating mid-pipe.","If responses come from your own server, ensure it does not close the body early (check compression middleware ordering)."],"exampleFix":"// before\nconst text = await new Response(fileStream.pipeThrough(new DecompressionStream(\"brotli\"))).text(); // truncated .br -> InvalidData (or silent empty)\n\n// after\nconst bytes = new Uint8Array(await new Response(fileStream).arrayBuffer());\nif (bytes.length < 8) throw new Error(\"brotli payload implausibly small — likely truncated\");\ntry {\n  const text = await new Response(new Blob([bytes]).stream().pipeThrough(new DecompressionStream(\"brotli\"))).text();\n} catch (e) {\n  throw new Error(`corrupt brotli asset (${bytes.length} bytes): ${e.message}`);\n}","handlingStrategy":"try-catch","validationCode":"const res = await fetch(url);\nconst enc = res.headers.get(\"content-encoding\");\nif (enc && enc !== \"br\" && enc !== \"gzip\" && enc !== \"deflate\") throw new Error(`unsupported content-encoding: ${enc}`);\nif (res.headers.has(\"content-length\") && Number(res.headers.get(\"content-length\")) < 4) throw new Error(\"body too small to be a valid compressed stream\");","typeGuard":null,"tryCatchPattern":"try { text = await decompress(bytes); } catch (e) { if (/brotli decompression failed/.test(String(e))) throw new Error(`corrupt/truncated brotli payload for ${url} — re-fetch the source`); throw e; }","preventionTips":["Verify sizes/checksums of downloaded .br assets before decompressing.","Validate Content-Encoding matches what you actually requested.","Remember error suppression: a silently empty result can be the same root cause as this error."],"tags":["decompression","brotli","decompressionstream","corrupt-data","web-streams"],"backgroundTag":"corrupt-compressed-data","analyzedSha":"a961cdec3b1948844414ebeecc697dcad76df2d1","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}