agalwood/Motrix · error · RangeError
Completed must end in completed
Error message
Completed must end in completed
What it means
For `TaskHistoryEventKind.Completed`, `toStatus` must be exactly `TaskStatus.Completed`. Throws this `RangeError` otherwise — a Completed event that lands anywhere else (e.g. `seeding`, `error`) is a logical contradiction. A BT task that finishes downloading but keeps seeding should use `StageChanged`, not `Completed`.
Source
Thrown at src/core/inspector-activity/validators.ts:231
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')
}
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(View on GitHub (pinned to 1a708ee577)
Solutions
- Reserve Completed for `toStatus === TaskStatus.Completed`.
- Use StageChanged for the download->seeding transition.
- Use Failed for terminal errors.
Example fix
// before
emit({ kind: TaskHistoryEventKind.Completed, fromStatus: TaskStatus.Downloading, toStatus: TaskStatus.Seeding })
// after
emit({ kind: TaskHistoryEventKind.StageChanged, fromStatus: TaskStatus.Downloading, toStatus: TaskStatus.Seeding }) Defensive patterns
Strategy: validation
Validate before calling
if (newStatus === TaskStatus.Completed) emit({ kind: TaskHistoryEventKind.Completed, /* ... */ })
else if (newStatus === TaskStatus.Error) emit({ kind: TaskHistoryEventKind.Failed, /* ... */ })
else emit({ kind: TaskHistoryEventKind.StageChanged, /* ... */ }) Prevention
- Map each terminal target status to its own event kind.
- Treat download->seeding as StageChanged, not Completed.
When it happens
Trigger: Emitting Completed when the task transitions to `seeding` (BT post-download) or `error`; usually because the producer fired Completed on engine `complete` regardless of the resolved target.
Common situations: BT workflows where 'download finished' means 'now seeding'; engine signals that map to error rather than completion; tests reusing Completed for any terminal transition.
Related errors
- Added must not have a fromStatus
- Started must enter an active status
- Paused must transition from active to paused
- Resumed must transition from paused to active
- Failed must end in error
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/8f61890590b14268.
Report an issue: GitHub.