agalwood/Motrix · error · AppError

TorrentParseFailed

TorrentParseFailed

Error message

Torrent file is too large

What it means

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.

Source

Thrown at src/core/torrent/torrent-parser.ts:14

import { extname } from 'node:path'
import { getLogger } from '@core/logger'
import { AppError, ErrorCode } from '@shared/errors'
import type { TorrentFileInfo, TorrentMeta } from '@shared/types/torrent'
import parseTorrent from 'parse-torrent'

const log = getLogger('torrent-parser')

const MAX_BASE64_SIZE = 50 * 1024 * 1024

export class TorrentParser {
  async parse(base64: string): Promise<TorrentMeta> {
    if (base64.length > MAX_BASE64_SIZE) {
      throw new AppError(
        ErrorCode.TorrentParseFailed,
        'Torrent file is too large'
      )
    }

    let parsed: Awaited<ReturnType<typeof parseTorrent>>
    try {
      const bytes = Buffer.from(base64, 'base64')
      parsed = await parseTorrent(new Uint8Array(bytes))
    } catch (err) {
      log.warn({ err }, 'failed to parse torrent')
      throw new AppError(
        ErrorCode.TorrentParseFailed,
        'Invalid torrent file',
        err
      )
    }

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Reject the file at the UI layer before reading it entirely — check the source file size and warn the user.
  2. If the torrent legitimately needs processing, raise MAX_BASE64_SIZE only if memory headroom is confirmed.
  3. Validate the source is a real `.torrent` and not a duplicated/concatenated payload.
  4. Prefer passing a Buffer/path to parseTorrent instead of base64 to avoid the 4/3 encoding inflation.

Example fix

// before
if (base64.length > MAX_BASE64_SIZE) {
  throw new AppError(ErrorCode.TorrentParseFailed, 'Torrent file is too large')
}

// after — size-check on the raw file before base64 encoding
const stat = await fs.stat(filePath)
if (stat.size > MAX_TORRENT_FILE_SIZE) {
  throw new AppError(ErrorCode.TorrentParseFailed, `Torrent file is too large (${stat.size} bytes)`)
}
Defensive patterns

Strategy: validation

Validate before calling

const MAX_TORRENT_FILE_SIZE = 50 * 1024 * 1024 // raw bytes
async function torrentWithinSize(fs, filePath) {
  const stat = await fs.stat(filePath)
  return stat.size <= MAX_TORRENT_FILE_SIZE
}
if (!(await torrentWithinSize(fs, filePath))) {
  // reject in the UI before base64-encoding

Type guard

function isTorrentTooLarge(e) { return e instanceof AppError && e.code === ErrorCode.TorrentParseFailed && /too large/.test(e.message) }

Try / catch

if (base64.length > MAX_BASE64_SIZE) {
  throw new AppError(ErrorCode.TorrentParseFailed, `Torrent file is too large (${base64.length} base64 chars)`)
}

Prevention

When it happens

Trigger: 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.

Common situations: Genuinely huge torrents (massive archives); a malformed caller doubling the base64; a wrapper that embeds the file twice; legacy torrents with extreme piece counts.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/7c38e1fed4ad788e. Report an issue: GitHub.