{"record":{"id":"7091c79817b217a6","repo":"agalwood/Motrix","slug":"kind-is-not-a-legal-history-event-kind","errorCode":null,"errorMessage":"kind is not a legal history event kind","messagePattern":"kind is not a legal history event kind","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"src/core/inspector-activity/validators.ts","lineNumber":171,"sourceCode":"    throw new RangeError(\n      `${label} JSON must not exceed ${maxJsonLength} characters`\n    )\n  }\n}\n\nexport function validateHistoryEventInput(input: TaskHistoryEventInput): void {\n  assertTaskId(input.taskId)\n  assertPositiveSafeInteger(input.eventOrdinal, 'eventOrdinal')\n  assertBoundedText(input.eventKey, 'eventKey', MAX_EVENT_KEY_LENGTH)\n  assertBoundedText(\n    input.runtimeGeneration,\n    'runtimeGeneration',\n    MAX_EVENT_KEY_LENGTH\n  )\n  assertPositiveSafeInteger(input.occurredAt, 'occurredAt')\n  assertNonNegativeSafeInteger(input.occurredMonotonicMs, 'occurredMonotonicMs')\n  if (!EVENT_KIND_VALUES.has(input.kind)) {\n    throw new RangeError('kind is not a legal history event kind')\n  }\n  if (!ACCURACY_VALUES.has(input.accuracy)) {\n    throw new RangeError('accuracy is not legal')\n  }\n  if (!DELIVERY_VALUES.has(input.delivery)) {\n    throw new RangeError('delivery is not legal')\n  }\n  assertStatus(input.fromStatus, 'fromStatus')\n  assertStatus(input.toStatus, 'toStatus')\n  if (input.toStatus === null) {\n    throw new RangeError('toStatus is required')\n  }\n  assertBoundedText(input.errorCode, 'errorCode', MAX_ERROR_CODE_LENGTH)\n  assertBoundedText(\n    input.errorMessage,\n    'errorMessage',\n    MAX_ERROR_MESSAGE_LENGTH\n  )","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/inspector-activity/validators.ts#L153-L189","documentation":"`validateHistoryEventInput` requires `input.kind` to be one of the `TaskHistoryEventKind` enum values: `added`, `started`, `paused`, `resumed`, `stage_changed`, `completed`, `failed`, `observed_state`. The set is built once from `Object.values(...)`. A non-matching kind throws this `RangeError` before any state-machine checks run.","triggerScenarios":"Submitting an event with a kind string from a foreign vocabulary, an old identifier (`'stop'` instead of `'paused'`), or accidentally passing the raw engine event type. Also fires when kind is `undefined`/empty after a bad deserialization.","commonSituations":"Bridging an external download engine's event names; replaying events from an older DB schema; tests using literals like `'started'` that later got renamed.","solutions":["Map the upstream event type through a lookup table that drops unmappable events.","Reference `TaskHistoryEventKind.X` instead of literals so renames are tracked by the compiler.","Quarantine events whose kind cannot be mapped and surface them in telemetry — do not submit them.","Add a migration that backfills any renamed enum values in durable storage."],"exampleFix":"// before\ninput.kind = engineEventType  // 'begin' — not in enum\n// after\nconst KIND_MAP: Record<string, TaskHistoryEventKind> = {\n  begin: TaskHistoryEventKind.Started,\n}\ninput.kind = KIND_MAP[engineEventType]\nif (input.kind === undefined) return","handlingStrategy":"type-guard","validationCode":"import { TaskHistoryEventKind } from '@shared/types/task-inspector-activity'\nconst KIND_VALUES = new Set(Object.values(TaskHistoryEventKind))\nfunction coerceKind(v: unknown): TaskHistoryEventKind | null {\n  return typeof v === 'string' && KIND_VALUES.has(v) ? (v as TaskHistoryEventKind) : null\n}","typeGuard":"import { TaskHistoryEventKind } from '@shared/types/task-inspector-activity'\nconst KIND_VALUES = new Set(Object.values(TaskHistoryEventKind))\nfunction isHistoryKind(v: unknown): v is TaskHistoryEventKind {\n  return typeof v === 'string' && KIND_VALUES.has(v)\n}","tryCatchPattern":null,"preventionTips":["Import `TaskHistoryEventKind` enum members; never inline the string values.","Translate external event types at the boundary.","Drop, don't submit, unmappable events."],"tags":["validation","range-error","enums","state-machine"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}