{"record":{"id":"660fa20416e3ca53","repo":"can1357/oh-my-pi","slug":"error-instanceof-error-error-message-string-660fa2","errorCode":null,"errorMessage":"${error instanceof Error ? error.message : String(error)}","messagePattern":"\\$\\{error instanceof Error \\? error\\.message : String\\(error\\)\\}","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/zstd.ts","lineNumber":18,"sourceCode":"import { promisify } from \"node:util\";\nimport * as zlib from \"node:zlib\";\nimport { ArchiveError } from \"../error\";\n\nconst zstdCompressAsync = promisify(zlib.zstdCompress);\nconst zstdDecompressAsync = promisify(zlib.zstdDecompress);\n\n/** zstd frame magic: 28 b5 2f fd. */\nexport function isZstd(bytes: Uint8Array): boolean {\n\treturn bytes.byteLength >= 4 && bytes[0] === 0x28 && bytes[1] === 0xb5 && bytes[2] === 0x2f && bytes[3] === 0xfd;\n}\n\n/** Decompress one zstd frame, bounded to `maxOutput` bytes. */\nexport async function zstdDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array> {\n\ttry {\n\t\treturn await zstdDecompressAsync(bytes, { maxOutputLength: Math.max(maxOutput, 1) });\n\t} catch (error) {\n\t\tthrow new ArchiveError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\n/** Compress bytes as one zstd frame (tar.zst writing). */\nexport function zstdCompress(bytes: Uint8Array): Promise<Uint8Array> {\n\treturn zstdCompressAsync(bytes);\n}\n","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/zstd.ts#L1-L26","documentation":"zstdDecompress wraps any failure from the underlying async zstd decoder into an ArchiveError carrying the native decoder's message. This is the surface for all zstd frame problems: corrupt frames, magic mismatch, exceeding maxOutputLength, or unsupported frame parameters.","triggerScenarios":"Calling zstdDecompress on bytes that are not a valid zstd frame; a frame whose decompressed size exceeds maxOutputLength; truncated .tar.zst or .zst payloads.","commonSituations":"Corrupt uploads; decompression-bomb protection tripping maxOutputLength; files with wrong extension decompressed with the wrong codec; zstd frames produced with dictionaries or parameters the decoder rejects.","solutions":["Verify the input starts with the zstd magic (0x28 B5 2F FD) before calling","Raise maxOutput if the native message indicates the output limit was hit and the input is trusted","Re-download/re-extract the file if the message indicates corruption","Ensure you are using the right codec for the file (zstd vs gzip vs xz)"],"exampleFix":"// before\nawait zstdDecompress(bytes, 10 * 1024 * 1024); // bombs out on large frames\n// after\nif (!(bytes[0] === 0x28 && bytes[1] === 0xb5 && bytes[2] === 0x2f && bytes[3] === 0xfd)) throw new Error('not zstd');\nawait zstdDecompress(bytes, 256 * 1024 * 1024);","handlingStrategy":"validation","validationCode":"function isZstdFrame(b: Uint8Array): boolean {\n  return b.byteLength >= 4 && b[0] === 0x28 && b[1] === 0xb5 && b[2] === 0x2f && b[3] === 0xfd;\n}\nif (!isZstdFrame(bytes)) throw new Error('not a zstd frame');","typeGuard":"function isZstdFrame(b: Uint8Array): boolean {\n  return b.byteLength >= 4 && b[0] === 0x28 && b[1] === 0xb5 && b[2] === 0x2f && b[3] === 0xfd;\n}","tryCatchPattern":"try {\n  return await zstdDecompress(bytes, maxOutput);\n} catch (err) {\n  if (err instanceof ArchiveError) {\n    if (/output/i.test(err.message)) return null; // hit maxOutput: bomb or limit too low\n    return null; // corrupt/invalid frame\n  }\n  throw err;\n}","preventionTips":["Check the zstd magic bytes before decoding","Size maxOutput to the expected uncompressed data plus headroom","Detect codec by magic bytes (xz 0xFD '7zXZ', gzip 0x1F 0x8B, zstd 0x28 B5 2F FD) rather than filename"],"tags":["zstd","decompression","archive","wrapper"],"backgroundTag":"zstd-frame-invalid","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}