agalwood/Motrix · error · RangeError

Paused must transition from active to paused

Error message

Paused must transition from active to paused

What it means

For `TaskHistoryEventKind.Paused`, all three must hold: `fromStatus` is non-null, `fromStatus` is in `ACTIVE_RESUME_STATUSES` (`fetching_metadata`, `downloading`, `finalizing`, `seeding`), and `toStatus === TaskStatus.Paused`. Throws this `RangeError` otherwise — you cannot pause from an already-paused, terminal, or queued state.

Source

Thrown at src/core/inspector-activity/validators.ts:218

  switch (input.kind) {
    case TaskHistoryEventKind.Added:
      if (input.fromStatus !== null) {
        throw new RangeError('Added must not have a fromStatus')
      }
      break
    case TaskHistoryEventKind.Started:
      if (!ACTIVE_RESUME_STATUSES.has(input.toStatus)) {
        throw new RangeError('Started must enter an active status')
      }
      break
    case TaskHistoryEventKind.Paused:
      if (
        input.fromStatus === null ||
        !ACTIVE_RESUME_STATUSES.has(input.fromStatus) ||
        input.toStatus !== TaskStatus.Paused
      ) {
        throw new RangeError('Paused must transition from active to paused')
      }
      break
    case TaskHistoryEventKind.Resumed:
      if (
        input.fromStatus !== TaskStatus.Paused ||
        !ACTIVE_RESUME_STATUSES.has(input.toStatus)
      ) {
        throw new RangeError('Resumed must transition from paused to active')
      }
      break
    case TaskHistoryEventKind.Completed:
      if (input.toStatus !== TaskStatus.Completed) {
        throw new RangeError('Completed must end in completed')
      }
      break
    case TaskHistoryEventKind.Failed:
      if (input.toStatus !== TaskStatus.Error) {
        throw new RangeError('Failed must end in error')

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Only emit Paused when the prior status is active and the new status is paused; otherwise emit the matching kind (or drop the event).
  2. Track the persisted status and compare before emitting.
  3. Quarantine out-of-order events during recovery.

Example fix

// before
emit({ kind: TaskHistoryEventKind.Paused, fromStatus: TaskStatus.Paused, toStatus: TaskStatus.Paused })
// after
if (currentStatus === TaskStatus.Paused) return  // already paused, no-op
emit({ kind: TaskHistoryEventKind.Paused, fromStatus: currentStatus, toStatus: TaskStatus.Paused })
Defensive patterns

Strategy: validation

Validate before calling

const ACTIVE = new Set([TaskStatus.FetchingMetadata, TaskStatus.Downloading, TaskStatus.Finalizing, TaskStatus.Seeding])
function canPause(from: TaskStatus | null): boolean {
  return from !== null && ACTIVE.has(from)
}

Prevention

When it happens

Trigger: A Paused event whose `fromStatus` is itself `paused` (double-pause), `completed`/`error` (pausing a terminal task), or `null`, or whose `toStatus` is not `paused` — typically the producer forwarded an engine pause notification without checking the prior status.

Common situations: Engine-level pause/idle signals arriving after the task already transitioned terminal; replaying events out of order; tests that don't set fromStatus.

Related errors


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