{"record":{"id":"7c38e1fed4ad788e","repo":"agalwood/Motrix","slug":"torrentparsefailed","errorCode":"TorrentParseFailed","errorMessage":"Torrent file is too large","messagePattern":"Torrent file is too large","errorType":"exception","errorClass":"AppError","httpStatus":null,"severity":"error","filePath":"src/core/torrent/torrent-parser.ts","lineNumber":14,"sourceCode":"import { extname } from 'node:path'\nimport { getLogger } from '@core/logger'\nimport { AppError, ErrorCode } from '@shared/errors'\nimport type { TorrentFileInfo, TorrentMeta } from '@shared/types/torrent'\nimport parseTorrent from 'parse-torrent'\n\nconst log = getLogger('torrent-parser')\n\nconst MAX_BASE64_SIZE = 50 * 1024 * 1024\n\nexport class TorrentParser {\n  async parse(base64: string): Promise<TorrentMeta> {\n    if (base64.length > MAX_BASE64_SIZE) {\n      throw new AppError(\n        ErrorCode.TorrentParseFailed,\n        'Torrent file is too large'\n      )\n    }\n\n    let parsed: Awaited<ReturnType<typeof parseTorrent>>\n    try {\n      const bytes = Buffer.from(base64, 'base64')\n      parsed = await parseTorrent(new Uint8Array(bytes))\n    } catch (err) {\n      log.warn({ err }, 'failed to parse torrent')\n      throw new AppError(\n        ErrorCode.TorrentParseFailed,\n        'Invalid torrent file',\n        err\n      )\n    }\n","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/torrent/torrent-parser.ts#L1-L32","documentation":"Thrown by torrent-parser.ts:14 when the base64-encoded torrent input exceeds MAX_BASE64_SIZE (50 MiB). TorrentParser.parse guards the parse-torrent library against pathological memory use by rejecting oversized inputs before decoding. The torrent may be otherwise valid; it is simply too large to process.","triggerScenarios":"User supplies a `.torrent` whose base64 encoding is > 50 MiB (very large multi-file torrent, or a torrent with huge padding/piece lists); an external caller pushes an oversized payload; the base64 was concatenated/duplicated by a bug.","commonSituations":"Genuinely huge torrents (massive archives); a malformed caller doubling the base64; a wrapper that embeds the file twice; legacy torrents with extreme piece counts.","solutions":["Reject the file at the UI layer before reading it entirely — check the source file size and warn the user.","If the torrent legitimately needs processing, raise MAX_BASE64_SIZE only if memory headroom is confirmed.","Validate the source is a real `.torrent` and not a duplicated/concatenated payload.","Prefer passing a Buffer/path to parseTorrent instead of base64 to avoid the 4/3 encoding inflation."],"exampleFix":"// before\nif (base64.length > MAX_BASE64_SIZE) {\n  throw new AppError(ErrorCode.TorrentParseFailed, 'Torrent file is too large')\n}\n\n// after — size-check on the raw file before base64 encoding\nconst stat = await fs.stat(filePath)\nif (stat.size > MAX_TORRENT_FILE_SIZE) {\n  throw new AppError(ErrorCode.TorrentParseFailed, `Torrent file is too large (${stat.size} bytes)`)\n}","handlingStrategy":"validation","validationCode":"const MAX_TORRENT_FILE_SIZE = 50 * 1024 * 1024 // raw bytes\nasync function torrentWithinSize(fs, filePath) {\n  const stat = await fs.stat(filePath)\n  return stat.size <= MAX_TORRENT_FILE_SIZE\n}\nif (!(await torrentWithinSize(fs, filePath))) {\n  // reject in the UI before base64-encoding","typeGuard":"function isTorrentTooLarge(e) { return e instanceof AppError && e.code === ErrorCode.TorrentParseFailed && /too large/.test(e.message) }","tryCatchPattern":"if (base64.length > MAX_BASE64_SIZE) {\n  throw new AppError(ErrorCode.TorrentParseFailed, `Torrent file is too large (${base64.length} base64 chars)`)\n}","preventionTips":["Check the raw file size before base64-encoding it.","Pass a Buffer/path to parseTorrent to avoid 4/3 base64 inflation.","Raise MAX_BASE64_SIZE only if memory headroom is confirmed.","Reject oversized torrents in the upload UI with a clear message."],"tags":["torrent","validation","parser","size-limit","memory"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}