{"record":{"id":"e4d3b355e6083ab7","repo":"moeru-ai/airi","slug":"the-motion-sample-rate-must-be-positive","errorCode":null,"errorMessage":"The motion sample rate must be positive.","messagePattern":"The motion sample rate must be positive\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/motion-driver-magic/src/shared/var.ts","lineNumber":73,"sourceCode":"\n  return solvePositiveDefinite(gram, cross, 'The VAR fit is numerically singular. Increase the ridge penalty.')\n}\n\nfunction createResiduals(frames: readonly number[][], coefficients: readonly number[][], order: number): number[][] {\n  const channelCount = frames[0].length\n  const residuals: number[][] = []\n  for (let frameIndex = order; frameIndex < frames.length; frameIndex++) {\n    const feature = createAutoregressiveFeature(frames, order, channelCount, frameIndex)\n    const prediction = predictAutoregressiveValues(coefficients, feature)\n    residuals.push(frames[frameIndex].map((value, channel) => value - prediction[channel]))\n  }\n  return residuals\n}\n\n/** Fits the VAR parameters that both public methods use. */\nexport function fitVarParameters(sequence: TrainingSequence, options: VarFitOptions): VarParameters {\n  if (!Number.isFinite(sequence.sampleRateHz) || sequence.sampleRateHz <= 0)\n    throw new Error('The motion sample rate must be positive.')\n  if (options.order < 1 || !Number.isInteger(options.order))\n    throw new Error('The VAR order must be a positive integer.')\n\n  const frames = sequence.frames\n  if (frames.length === 0 || frames[0].length === 0)\n    throw new Error('The motion sequence must contain at least one value.')\n  if (frames.some(frame => frame.length !== frames[0].length))\n    throw new Error('Every motion frame must have the same number of values.')\n\n  const channels = createMotionChannels(frames)\n  if (channels.length === 0)\n    throw new Error('The current motion has no changing channels.')\n  if (frames.length <= options.order + 1)\n    throw new Error('The current motion is too short for this VAR order.')\n\n  const baselineFrame = createBaselineFrame(frames)\n  const trainingFrames = frames.map(frame => channels.map(\n    channel => (frame[channel.valueIndices[0]] - channel.mean) / channel.scale,","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/moeru-ai/airi/blob/9c213115f8bd0fff9e6eabab02b077ac32da21be/packages/motion-driver-magic/src/shared/var.ts#L55-L91","documentation":"VAR fitting divides time by `sampleRateHz` to build lag structures and time indices; a non-finite or non-positive sample rate makes every derived quantity meaningless. `fitVarParameters` validates it first, before touching the frames.","triggerScenarios":"Passing a `TrainingSequence` whose `sampleRateHz` is 0, negative, NaN, or Infinity — e.g. sampleRate computed as `frameCount / duration` with duration 0, or a config field left unset (undefined coerced into arithmetic giving NaN).","commonSituations":"Division by a zero-length recording duration; forgetting to set sampleRateHz when constructing a TrainingSequence by hand; parsing a config where sample rate is an empty string; unit mix-up (seconds vs milliseconds) producing 0 after flooring.","solutions":["Set `sampleRateHz` to a positive finite number matching the capture rate (e.g. 30 or 60).","Guard the computation: only build the sequence when duration > 0 and rate is finite.","Validate the sequence with a schema before fitting (`sampleRateHz: finite, > 0`).","Check units — if storing milliseconds, convert before passing (e.g. 0.033ms -> 30Hz)."],"exampleFix":"// before\nfitVarParameters({ frames, sampleRateHz: frames.length / duration }, opts)\n// after\nconst rate = frames.length / duration\nif (!Number.isFinite(rate) || rate <= 0)\n  throw new Error('Capture duration must be positive')\nfitVarParameters({ frames, sampleRateHz: rate }, opts)","handlingStrategy":"validation","validationCode":"function isValidSampleRate(seq: TrainingSequence): boolean {\n  return Number.isFinite(seq.sampleRateHz) && seq.sampleRateHz > 0\n}","typeGuard":null,"tryCatchPattern":"try {\n  fitVarParameters(seq, options)\n} catch (error) {\n  if (error instanceof Error && error.message.includes('sample rate')) {\n    return fitVarParameters({ ...seq, sampleRateHz: 30 }, options)\n  }\n  throw error\n}","preventionTips":["Never compute sampleRateHz with a possibly-zero denominator; guard duration > 0.","Validate sequence with a schema (finite, positive rate) before fitting.","Standardize units (Hz) at the capture boundary, converting once.","Reject undefined/NaN rates at sequence construction time, not at fit time."],"tags":["validation","options","var","motion"],"backgroundTag":"invalid-sample-rate","analyzedSha":"9c213115f8bd0fff9e6eabab02b077ac32da21be","analyzedAt":"2026-09-02T04:27:24.639Z","contentChangedAt":"2026-09-02T04:27:24.639Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}