{"record":{"id":"3e1680583948c2c9","repo":"can1357/oh-my-pi","slug":"rar5-dictionary-is-too-large-dictionarysize-by","errorCode":null,"errorMessage":"RAR5 dictionary is too large (${dictionarySize} bytes)","messagePattern":"RAR5 dictionary is too large \\((.+?) bytes\\)","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/rar.ts","lineNumber":365,"sourceCode":"\t\t\t\tmtimeMs = readUInt32LE(bytes, cursor.offset) * 1000;\n\t\t\t\tcursor.offset += 4;\n\t\t\t}\n\t\t\tlet dataCrc: number | undefined;\n\t\t\tif ((fileFlags & 4) !== 0) {\n\t\t\t\tneed(cursor.offset, 4, extraStart, \"RAR5 data CRC32\");\n\t\t\t\tdataCrc = readUInt32LE(bytes, cursor.offset);\n\t\t\t\tcursor.offset += 4;\n\t\t\t}\n\t\t\tconst compression = readVint(bytes, cursor, extraStart, \"compression information\");\n\t\t\tlet version = compression & 0x3f;\n\t\t\tif (version === 1 && (compression & 0x100000) !== 0) version = 0;\n\t\t\tconst solid = (compression & 0x40) !== 0;\n\t\t\tconst method = (compression >>> 7) & 7;\n\t\t\tconst dictionaryPower = (compression >>> 10) & 0x1f;\n\t\t\tlet dictionarySize = 128 * 1024 * 2 ** dictionaryPower;\n\t\t\tif ((compression & 0x3f) === 1) dictionarySize += (dictionarySize * ((compression >>> 15) & 0x1f)) / 32;\n\t\t\tif (!Number.isSafeInteger(dictionarySize) || dictionarySize > options.limits.maxInMemorySize) {\n\t\t\t\tthrow new ArchiveError(`RAR5 dictionary is too large (${dictionarySize} bytes)`);\n\t\t\t}\n\t\t\tconst hostOs = readVint(bytes, cursor, extraStart, \"host OS\");\n\t\t\tconst nameSize = readVint(bytes, cursor, extraStart, \"file name size\");\n\t\t\tassertArchivePathBytes(nameSize, \"member path\", options.limits.maxPathBytes);\n\t\t\tneed(cursor.offset, nameSize, extraStart, \"RAR5 file name\");\n\t\t\tlet rawPath: string;\n\t\t\ttry {\n\t\t\t\trawPath = UTF8.decode(bytes.subarray(cursor.offset, cursor.offset + nameSize));\n\t\t\t} catch {\n\t\t\t\tthrow new ArchiveError(\"Invalid RAR5 UTF-8 member name\");\n\t\t\t}\n\t\t\tcursor.offset += nameSize;\n\t\t\tlet linkTarget: string | undefined;\n\t\t\tfor (const extra of readExtraRecords(bytes, extraStart, headerEnd)) {\n\t\t\t\tconst extraCursor = { offset: extra.start };\n\t\t\t\tif (extra.type === 1) throw new ArchiveError(`Encrypted RAR5 member '${rawPath}' is not supported`);\n\t\t\t\tif (extra.type === 3) {\n\t\t\t\t\tconst timeFlags = readVint(bytes, extraCursor, extra.end, \"time flags\");","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/rar.ts#L347-L383","documentation":"Each RAR5 compressed member declares a LZ dictionary size derived from the compression-info bits (128 KiB * 2^power, optionally extended). If the computed dictionary is not a safe integer or exceeds options.limits.maxInMemorySize, the library refuses because members are decompressed in memory.","triggerScenarios":"Reading a RAR5 member compressed with a very large dictionary (dictionaryPower near 0x1f, i.e. dictionaries of gigabytes) while options.limits.maxInMemorySize is smaller than that dictionary.","commonSituations":"Users maximizing compression ratio with `rar -md1g` or larger on huge inputs; archives created with modern WinRAR 7 64-bit dictionary sizes parsed by a library configured with a small memory cap; strict maxInMemorySize set for safety in server environments.","solutions":["Raise options.limits.maxInMemorySize when the archive is trusted and the dictionary size is acceptable","Re-compress the archive with a smaller dictionary (`rar -md<m>` default is small)","Reject such archives upstream and fall back to the unrar CLI"],"exampleFix":"// before\nconst records = readRar(bytes, { limits: { maxInMemorySize: 64 * 1024 * 1024 } });\n// after\nconst records = readRar(bytes, { limits: { maxInMemorySize: 1024 * 1024 * 1024 } }); // allow 1GiB dictionaries","handlingStrategy":"validation","validationCode":"// raise the in-memory cap if trusted archives use big dictionaries\nconst options = { limits: { maxInMemorySize: 512 * 1024 * 1024 } };","typeGuard":null,"tryCatchPattern":"try {\n  const records = readRar(bytes, options);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('dictionary is too large')) {\n    const m = /\\((\\d+) bytes\\)/.exec(err.message);\n    // surface required size to caller, or re-compress externally\n  } else throw err;\n}","preventionTips":["Set maxInMemorySize generously on trusted inputs, tightly on untrusted ones","Avoid very large -md dictionary settings when targeting parsers","Document the memory cap for consumers of your service"],"tags":["rar5","memory-limit","dictionary-size","limits"],"backgroundTag":"archive-size-limit-exceeded","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}