agalwood/Motrix · error · TypeError

aria2 addTorrent gid must contain exactly 16 hexadecimal cha

Error message

aria2 addTorrent gid must contain exactly 16 hexadecimal characters

What it means

Thrown as a TypeError by Aria2Adapter.addTorrent when params.extraEngineOptions?.gid is defined but is not a string (e.g. it's an array or number). This is a type-safety guard: extraEngineOptions is typed as Record<string, string | string[]>, so a gid could arrive as a string[] from the engine-agnostic passthrough. The adapter requires gid to be a single string before it can be validated against the 16-hex pattern.

Source

Thrown at src/core/engine/aria2/aria2-adapter.ts:388

      throw err
    }
    const raw = opts['bt-tracker']
    if (!raw) return []
    return raw
      .split(',')
      .map((s) => s.trim())
      .filter((s) => s.length > 0)
  }

  async getGlobalStats(): Promise<GlobalStats> {
    const raw = await this.rpc.getGlobalStat()
    return translateGlobalStat(raw)
  }

  async addTorrent(params: AddTorrentParams): Promise<string> {
    const extraGid = params.extraEngineOptions?.gid
    if (extraGid !== undefined && typeof extraGid !== 'string') {
      throw new TypeError(
        'aria2 addTorrent gid must contain exactly 16 hexadecimal characters'
      )
    }
    const requestedGid =
      params.gid ?? (typeof extraGid === 'string' ? extraGid : undefined)
    const opts: Record<string, string> = {
      dir: params.saveDir,
      pause: String(params.pause ?? false),
    }
    if (requestedGid !== undefined) {
      if (!/^[0-9a-fA-F]{16}$/.test(requestedGid)) {
        throw new TypeError(
          'aria2 addTorrent gid must contain exactly 16 hexadecimal characters'
        )
      }
    }
    if (params.selectedFiles?.length) {
      opts['select-file'] = params.selectedFiles.join(',')

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Ensure extraEngineOptions.gid is a single string, not an array — use params.gid directly instead of extraEngineOptions.gid for reserved GIDs
  2. If constructing options programmatically, coerce gid to a string before passing: String(gid)
  3. Use the dedicated params.gid field (typed as string) rather than the generic extraEngineOptions passthrough

Example fix

// before
await adapter.addTorrent({ ..., extraEngineOptions: { gid: ['0000000000000001'] } })
// after
await adapter.addTorrent({ ..., gid: '0000000000000001' })
Defensive patterns

Strategy: type-guard

Validate before calling

function normalizeGid(gid: unknown): string | undefined {
  if (gid === undefined) return undefined
  if (typeof gid !== 'string') {
    throw new TypeError('gid must be a string')
  }
  return gid
}
// Use params.gid directly instead of extraEngineOptions.gid

Type guard

function isStringGid(value: unknown): value is string {
  return typeof value === 'string'
}

Try / catch

try {
  await adapter.addTorrent(params)
} catch (e) {
  if (e instanceof TypeError && e.message.includes('gid must contain')) {
    // Fix the gid type and retry
    params.gid = String(params.extraEngineOptions?.gid ?? '')
    delete params.extraEngineOptions?.gid
    await adapter.addTorrent(params)
  } else throw e
}

Prevention

When it happens

Trigger: addTorrent is called with extraEngineOptions containing a gid key whose value is a string array (or any non-string type), e.g. { gid: ['abc123'] } passed through the shell-supplied options passthrough.

Common situations: A plugin or shell layer passes engine options as arrays (valid for multi-value aria2 options like header) but includes gid as an array; a serialization layer converts single values to arrays; incorrect typing at a boundary that constructs AddTorrentParams.

Related errors


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