agalwood/Motrix · warning · AppError

TaskNotFound

TaskNotFound

Error message

task ${taskId} not found for magnet metadata swap

What it means

Thrown by swap-magnet-metadata-for-bt.ts:127 when `db.getTask(taskId)` returns null at the entry of a magnet-metadata-swap operation. The task targeted for swapping its MetadataReady magnet instance for a bt_download instance does not exist.

Source

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

  input: SwapMagnetMetadataInput,
  deps: SwapMagnetMetadataDeps
): Promise<{ gid: string }> {
  const { taskId, base64, selectedFiles, saveDir, name } = input
  const {
    db,
    taskManager,
    adapter,
    magnetTracker,
    finalNamePicker,
    torrentMetaStore,
    publishTaskUpdate,
    publishTaskUpdateNow,
    recordTransition,
  } = deps

  const existing = db.getTask(taskId)
  if (!existing) {
    throw new AppError(
      ErrorCode.TaskNotFound,
      `task ${taskId} not found for magnet metadata swap`
    )
  }

  if (
    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 (

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Verify the task exists in the renderer before showing the swap confirmation, and dismiss the dialog on task-deleted events.
  2. Treat TaskNotFound as a clean no-op (log + close the window) instead of a hard error.
  3. Guard the IPC entrypoint with a presence check and return a benign error to the renderer.
  4. Ensure clear-stopped-tasks and swap cannot run against the same task concurrently.

Example fix

// before
const existing = db.getTask(taskId)
if (!existing) {
  throw new AppError(ErrorCode.TaskNotFound, `task ${taskId} not found for magnet metadata swap`)
}

// after — benign no-op for stale confirmations
const existing = db.getTask(taskId)
if (!existing) {
  deps.log.warn({ taskId }, 'swap ignored: task no longer exists')
  return { outcome: 'noop', reason: 'task_missing' }
}
Defensive patterns

Strategy: validation

Validate before calling

function swapTargetExists(db, taskId) { return Boolean(db.getTask(taskId)) }

Type guard

function isSwapTaskNotFound(e) { return e instanceof AppError && e.code === ErrorCode.TaskNotFound && /magnet metadata swap/.test(e.message) }

Try / catch

const existing = db.getTask(taskId)
if (!existing) {
  deps.log.warn({ taskId }, 'swap ignored: task no longer exists')
  return { outcome: 'noop', reason: 'task_missing' }
}

Prevention

When it happens

Trigger: Swap requested for a taskId that was deleted between the user confirming and the swap call; a stale UI confirmation window; a typoed/fabricated taskId from an external caller; the task was cleared by clear-stopped-tasks.

Common situations: User confirmed a file selection, then deleted the task before the swap ran; renderer holding a stale task reference after a bulk clear; cross-window IPC with an outdated id.

Related errors


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