agalwood/Motrix · error · RangeError
${label} is not a legal task status
Error message
${label} is not a legal task status What it means
`assertStatus` allows `null` (status not applicable) or any value present in the `TaskStatus` enum: `queued`, `fetching_metadata`, `metadata_ready`, `downloading`, `finalizing`, `seeding`, `paused`, `completed`, `error`, `removed`. It throws this `RangeError` when the value is a non-null string outside that set. This protects the SQLite `status` column's CHECK constraint and the downstream state-machine invariants. `label` is `fromStatus` or `toStatus`.
Source
Thrown at src/core/inspector-activity/validators.ts:134
value: string | null,
label: string,
maxLength: number
): void {
if (value === null) return
if (
typeof value !== 'string' ||
value.length === 0 ||
value.length > maxLength
) {
throw new RangeError(
`${label} must contain between 1 and ${maxLength} characters`
)
}
}
function assertStatus(value: TaskStatus | null, label: string): void {
if (value !== null && !STATUS_VALUES.has(value)) {
throw new RangeError(`${label} is not a legal task status`)
}
}
function assertBoundedDetailParams(
value: Record<string, string> | null,
label: string,
maxJsonLength: number
): void {
if (value === null) return
if (
typeof value !== 'object' ||
Array.isArray(value) ||
Object.values(value).some((entry) => typeof entry !== 'string')
) {
throw new RangeError(`${label} must be a flat string record`)
}
const serialized = JSON.stringify(value)
if (serialized.length > maxJsonLength) {View on GitHub (pinned to 1a708ee577)
Solutions
- Map the incoming status through a translation table whose keys cover every foreign value, falling through to a known default.
- If the source is local, reference `TaskStatus.X` instead of a string literal so the compiler tracks renames.
- Drop or quarantine events with unmappable statuses rather than passing them to the validator.
- Re-run any migration that backfills old status identifiers.
Example fix
// before
input.fromStatus = engineState // 'running' — not in TaskStatus
// after
const FROM_ENGINE: Record<string, TaskStatus> = {
running: TaskStatus.Downloading,
stopped: TaskStatus.Paused,
}
input.fromStatus = FROM_ENGINE[engineState] ?? null Defensive patterns
Strategy: type-guard
Validate before calling
import { TaskStatus } from '@shared/types/task'
const STATUS_VALUES = new Set(Object.values(TaskStatus))
function coerceStatus(v: unknown): TaskStatus | null {
return typeof v === 'string' && STATUS_VALUES.has(v) ? (v as TaskStatus) : null
} Type guard
import { TaskStatus } from '@shared/types/task'
const STATUS_VALUES = new Set(Object.values(TaskStatus))
function isTaskStatus(v: unknown): v is TaskStatus {
return typeof v === 'string' && STATUS_VALUES.has(v)
} Prevention
- Never hardcode status strings — import `TaskStatus` enum members.
- Translate foreign statuses at the engine boundary, not at the validator.
- Add a snapshot/golden test of the status vocabulary so renames surface in CI.
When it happens
Trigger: Submitting a `TaskHistoryEventInput` whose `fromStatus`/`toStatus` carries a value outside the enum — e.g. an old serialized name (`'fetching'`), a foreign status (`'running'`), or a numeric status code that should have been translated. Surfaces when replaying history from an older schema or bridging an external engine's status vocabulary.
Common situations: Version drift: an event written under a previous release where a status had a different identifier; consuming a third-party engine's status enum directly; tests with hardcoded string literals that drift from the enum.
Related errors
- kind is not a legal history event kind
- accuracy is not legal
- delivery is not legal
- toStatus is required
- Added must not have a fromStatus
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/064c9a52e9e47f81.
Report an issue: GitHub.