{"record":{"id":"7e682887dd49e727","repo":"agalwood/Motrix","slug":"taskid-must-be-a-string","errorCode":null,"errorMessage":"taskId must be a string","messagePattern":"taskId must be a string","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"src/core/inspector-activity/validators.ts","lineNumber":34,"sourceCode":"export const MAX_ERROR_MESSAGE_LENGTH = 2_048\nexport const MAX_ERROR_DETAIL_KEY_LENGTH = 128\nexport const MAX_ERROR_DETAIL_PARAMS_JSON_LENGTH = 2_048\nexport const MAX_SAMPLE_FLAGS = 2_147_483_647\n\nconst STATUS_VALUES = new Set<string>(Object.values(TaskStatus))\nconst EVENT_KIND_VALUES = new Set<string>(Object.values(TaskHistoryEventKind))\nconst ACCURACY_VALUES = new Set<string>(Object.values(TaskHistoryAccuracy))\nconst DELIVERY_VALUES = new Set<string>(Object.values(TaskHistoryDelivery))\nconst ACTIVE_RESUME_STATUSES = new Set<TaskStatus>([\n  TaskStatus.FetchingMetadata,\n  TaskStatus.Downloading,\n  TaskStatus.Finalizing,\n  TaskStatus.Seeding,\n])\n\nexport function assertTaskId(taskId: string): string {\n  if (typeof taskId !== 'string') {\n    throw new RangeError('taskId must be a string')\n  }\n  if (taskId.length > MAX_TASK_ID_LENGTH) {\n    throw new RangeError(\n      `taskId must contain between 1 and ${MAX_TASK_ID_LENGTH} characters`\n    )\n  }\n  const normalized = taskId.trim()\n  if (normalized.length === 0 || normalized.length > MAX_TASK_ID_LENGTH) {\n    throw new RangeError(\n      `taskId must contain between 1 and ${MAX_TASK_ID_LENGTH} characters`\n    )\n  }\n  return normalized\n}\n\nexport function assertPositiveSafeInteger(\n  value: number,\n  label: string","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/inspector-activity/validators.ts#L16-L52","documentation":"RangeError from assertTaskId when the argument is not a string. This is a low-level validator used to gate IPC input; it deliberately throws RangeError (not AppError) for malformed primitives before any task lookup occurs.","triggerScenarios":"assertTaskId is called with a value where typeof !== 'string' — e.g. a number, undefined, null, object, or boolean.","commonSituations":"An IPC payload passed a numeric task id; a missing field defaulted to undefined; deserialization produced a non-string; a caller passed an object whose taskId field was unboxed incorrectly.","solutions":["Coerce or stringify the taskId before calling: String(value).","Validate at the boundary that taskId is a string and reject earlier.","Fix the sender to always send taskId as a string."],"exampleFix":"// before\nassertTaskId(payload.taskId) // payload.taskId is 12345 -> RangeError\n\n// after\nassertTaskId(typeof payload.taskId === 'number' ? String(payload.taskId) : payload.taskId)","handlingStrategy":"type-guard","validationCode":"// Coerce to string before validating.\nconst id = typeof raw === 'number' ? String(raw) : raw\nif (typeof id !== 'string') { /* reject early */ }\nassertTaskId(id)","typeGuard":"function isStringTaskId(v: unknown): v is string {\n  return typeof v === 'string'\n}","tryCatchPattern":"try {\n  assertTaskId(maybeId)\n} catch (err) {\n  if (err instanceof RangeError && /must be a string/.test(err.message)) {\n    // reject the IPC payload; require a string taskId\n  } else throw err\n}","preventionTips":["Always serialize taskIds as strings over IPC.","Coerce numeric ids at the boundary.","Default missing ids to undefined and reject, not to a number."],"tags":["validation","task","range-error","typescript","ipc"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}