agalwood/Motrix · error · AppError

InvalidSelection

InvalidSelection

Error message

task ${taskId} is not a MetadataReady magnet selection

What it means

Thrown by swap-magnet-metadata-for-bt.ts:152 when the task is not a MetadataReady magnet selection: it requires `taskType === Magnet`, `aggStatus === MetadataReady`, exactly one instance, that instance's phase to be `MagnetMetadataResolution`, and its status to be `MetadataReady`. Any mismatch rejects the swap as an invalid selection.

Source

Thrown at src/core/torrent/swap-magnet-metadata-for-bt.ts:152

    magnetTracker.hasPendingSwapCleanup(taskId) ||
    existing.instances.some(isMagnetCleanupTombstoneHidden)
  ) {
    throw new AppError(
      ErrorCode.MagnetCleanupPending,
      `aria2 cleanup for a failed magnet swap is still pending for ` +
        `task ${taskId}; please retry confirmation shortly.`
    )
  }
  const previousMetadataInstance =
    existing.instances.length === 1 ? existing.instances[0] : undefined
  if (
    existing.task.taskType !== TaskType.Magnet ||
    existing.task.aggStatus !== TaskStatus.MetadataReady ||
    previousMetadataInstance?.phase !==
      TaskInstancePhase.MagnetMetadataResolution ||
    previousMetadataInstance.status !== TaskStatus.MetadataReady
  ) {
    throw new AppError(
      ErrorCode.InvalidSelection,
      `task ${taskId} is not a MetadataReady magnet selection`
    )
  }
  const existingFiles = db.getTaskFiles(taskId)
  const originalGraph = {
    task: existing.task,
    instances: existing.instances,
    files: existingFiles,
  }
  const originalDownloadTask = taskRowToDownloadTask(
    existing.task,
    existing.instances
  )
  const originalOwner = taskManager.getById(taskId)
  const torrentBytes = Buffer.from(base64, 'base64')

  // Complete every fallible local preparation step before destructively

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Refresh task state in the renderer before showing the swap confirm dialog and only enable it while the task is MetadataReady magnet.
  2. Subscribe to status/instance-change events and tear down the swap dialog when the task leaves the valid state.
  3. Treat InvalidSelection as a benign user-facing 'selection no longer valid' notice rather than a hard error.
  4. Ensure only one swap flow can run per task at a time.

Example fix

// before
if (existing.task.taskType !== TaskType.Magnet || existing.task.aggStatus !== TaskStatus.MetadataReady || previousMetadataInstance?.phase !== TaskInstancePhase.MagnetMetadataResolution || previousMetadataInstance?.status !== TaskStatus.MetadataReady) {
  throw new AppError(ErrorCode.InvalidSelection, `task ${taskId} is not a MetadataReady magnet selection`)
}

// after — renderer-side guard so the throw is never reached
const swappable = task.taskType === 'magnet' && task.aggStatus === 'metadata-ready'
ui.setSwapEnabled(taskId, swappable)
if (!swappable) return
Defensive patterns

Strategy: validation

Validate before calling

import { TaskType, TaskStatus, TaskInstancePhase } from '@shared/types'
function isSwappableMagnetSelection(task, instances) {
  if (task.taskType !== TaskType.Magnet) return false
  if (task.aggStatus !== TaskStatus.MetadataReady) return false
  if (instances.length !== 1) return false
  const inst = instances[0]
  return inst.phase === TaskInstancePhase.MagnetMetadataResolution
    && inst.status === TaskStatus.MetadataReady
}

Type guard

function isInvalidSelection(e) { return e instanceof AppError && e.code === ErrorCode.InvalidSelection }

Try / catch

if (!isSwappableMagnetSelection(existing.task, existing.instances)) {
  ui.notifyUser('selection_no_longer_valid')
  return { outcome: 'noop', reason: 'invalid_selection' }
}

Prevention

When it happens

Trigger: Swap requested on a task that already converted to bt_download; a magnet task still resolving metadata (not yet MetadataReady); a non-magnet task type; the metadata instance was already swapped or cancelled leaving multiple instances or a different phase.

Common situations: Stale confirmation window for a task that already moved state; double-swap attempt; user navigated away and back after a state change; IPC replay with outdated task state.

Related errors


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