agalwood/Motrix · error · RangeError

Failed must end in error

Error message

Failed must end in error

What it means

For `TaskHistoryEventKind.Failed`, `toStatus` must be exactly `TaskStatus.Error`. Throws this `RangeError` otherwise — a failure event must land the task in the error state. Non-error terminal statuses belong to other kinds.

Source

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

        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')
      }
      break
    case TaskHistoryEventKind.ObservedState:
      if (input.accuracy !== TaskHistoryAccuracy.Recovered) {
        throw new RangeError('Observed state must be recovered')
      }
      break
    case TaskHistoryEventKind.StageChanged:
      break
  }
}

export function normalizeTransferSamples(
  samples: readonly TaskTransferSample[]
): TaskTransferSample[] {
  return samples.map((sample, index) => ({
    t: assertPositiveSafeInteger(sample.t, `samples[${index}].t`),
    down: normalizeSpeed(sample.down, `samples[${index}].down`),

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Reserve Failed for `toStatus === TaskStatus.Error`.
  2. Use the appropriate kind for other terminal transitions (Completed, StageChanged).
  3. Translate the engine error code to `TaskStatus.Error` at the boundary.

Example fix

// before
emit({ kind: TaskHistoryEventKind.Failed, fromStatus: TaskStatus.Downloading, toStatus: TaskStatus.Removed })
// after
emit({ kind: TaskHistoryEventKind.Failed, fromStatus: TaskStatus.Downloading, toStatus: TaskStatus.Error })
Defensive patterns

Strategy: validation

Validate before calling

if (engineError) emit({ kind: TaskHistoryEventKind.Failed, toStatus: TaskStatus.Error, /* ... */ })

Prevention

When it happens

Trigger: Emitting Failed with `toStatus: TaskStatus.Completed` or `TaskStatus.Removed`; usually a producer firing Failed on any abort without checking whether the engine reported a clean finish or an error.

Common situations: Engine abort that the bridge maps to Removed rather than Error; tests reusing Failed for any unsuccessful outcome; status-translation bug mapping error to completed.

Related errors


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