moeru-ai/airi · error · Error

The motion sample rate must be positive.

Error message

The motion sample rate must be positive.

What it means

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.

Source

Thrown at packages/motion-driver-magic/src/shared/var.ts:73

  return solvePositiveDefinite(gram, cross, 'The VAR fit is numerically singular. Increase the ridge penalty.')
}

function createResiduals(frames: readonly number[][], coefficients: readonly number[][], order: number): number[][] {
  const channelCount = frames[0].length
  const residuals: number[][] = []
  for (let frameIndex = order; frameIndex < frames.length; frameIndex++) {
    const feature = createAutoregressiveFeature(frames, order, channelCount, frameIndex)
    const prediction = predictAutoregressiveValues(coefficients, feature)
    residuals.push(frames[frameIndex].map((value, channel) => value - prediction[channel]))
  }
  return residuals
}

/** Fits the VAR parameters that both public methods use. */
export function fitVarParameters(sequence: TrainingSequence, options: VarFitOptions): VarParameters {
  if (!Number.isFinite(sequence.sampleRateHz) || sequence.sampleRateHz <= 0)
    throw new Error('The motion sample rate must be positive.')
  if (options.order < 1 || !Number.isInteger(options.order))
    throw new Error('The VAR order must be a positive integer.')

  const frames = sequence.frames
  if (frames.length === 0 || frames[0].length === 0)
    throw new Error('The motion sequence must contain at least one value.')
  if (frames.some(frame => frame.length !== frames[0].length))
    throw new Error('Every motion frame must have the same number of values.')

  const channels = createMotionChannels(frames)
  if (channels.length === 0)
    throw new Error('The current motion has no changing channels.')
  if (frames.length <= options.order + 1)
    throw new Error('The current motion is too short for this VAR order.')

  const baselineFrame = createBaselineFrame(frames)
  const trainingFrames = frames.map(frame => channels.map(
    channel => (frame[channel.valueIndices[0]] - channel.mean) / channel.scale,

View on GitHub (pinned to 9c213115f8)

Solutions

  1. Set `sampleRateHz` to a positive finite number matching the capture rate (e.g. 30 or 60).
  2. Guard the computation: only build the sequence when duration > 0 and rate is finite.
  3. Validate the sequence with a schema before fitting (`sampleRateHz: finite, > 0`).
  4. Check units — if storing milliseconds, convert before passing (e.g. 0.033ms -> 30Hz).

Example fix

// before
fitVarParameters({ frames, sampleRateHz: frames.length / duration }, opts)
// after
const rate = frames.length / duration
if (!Number.isFinite(rate) || rate <= 0)
  throw new Error('Capture duration must be positive')
fitVarParameters({ frames, sampleRateHz: rate }, opts)
Defensive patterns

Strategy: validation

Validate before calling

function isValidSampleRate(seq: TrainingSequence): boolean {
  return Number.isFinite(seq.sampleRateHz) && seq.sampleRateHz > 0
}

Try / catch

try {
  fitVarParameters(seq, options)
} catch (error) {
  if (error instanceof Error && error.message.includes('sample rate')) {
    return fitVarParameters({ ...seq, sampleRateHz: 30 }, options)
  }
  throw error
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-09-02). Data as JSON: /api/errors/e4d3b355e6083ab7. Report an issue: GitHub.