moeru-ai/airi · error · Error
The motion samples must be in time order.
Error message
The motion samples must be in time order.
What it means
Like the source samples of a motion project, recording samples must be non-decreasing in atMs so the interpolator can locate the surrounding pair for any time. parseLive2DMotionRecording throws this error when any sample's atMs is less than its predecessor's.
Source
Thrown at packages/stage-ui/src/features/devtools/motion/live2d/composables/recording.ts:100
let input: unknown
try {
input = JSON.parse(raw)
}
catch {
throw new Error('The file does not contain valid JSON.')
}
const result = safeParse(live2dMotionRecordingSchema, input)
if (!result.success)
throw new Error('The file is not an AIRI Live2D motion recording.')
const { durationMs, samples } = result.output
if (samples[0].atMs !== 0)
throw new Error('The first motion sample must start at 0 ms.')
for (let index = 1; index < samples.length; index++) {
if (samples[index].atMs < samples[index - 1].atMs)
throw new Error('The motion samples must be in time order.')
}
if (samples.at(-1)!.atMs > durationMs)
throw new Error('A motion sample occurs after the recording duration.')
return result.output
}
/**
* Serializes a Live2D joystick recording as a readable JSON file.
*
* @example
* stringifyLive2DMotionRecording({ format: 'airi-live2d-motion/v6', ... })
* // => readable JSON ending with a newline
*/
export function stringifyLive2DMotionRecording(recording: ReadonlyLive2DMotionRecording): string {
return `${JSON.stringify(recording, null, 2)}\n`
}View on GitHub (pinned to 9c213115f8)
Solutions
- Sort samples by atMs ascending before parsing
- Fix the recording pipeline so samples are appended in chronological order
- Re-record the motion if the source data is genuinely corrupted
Example fix
// before parseLive2DMotionRecording(raw) // after const data = JSON.parse(raw) data.samples.sort((a, b) => a.atMs - b.atMs) parseLive2DMotionRecording(JSON.stringify(data))
Defensive patterns
Strategy: validation
Validate before calling
const data = JSON.parse(raw) data.samples.sort((a, b) => a.atMs - b.atMs) raw = JSON.stringify(data)
Type guard
const isSortedByAtMs = (samples) => samples.every((s, i) => i === 0 || s.atMs >= samples[i - 1].atMs)
Try / catch
try {
const recording = parseLive2DMotionRecording(raw)
}
catch (error) {
if (error.message === 'The motion samples must be in time order.') {
const data = JSON.parse(raw)
data.samples.sort((a, b) => a.atMs - b.atMs)
raw = JSON.stringify(data)
return parseLive2DMotionRecording(raw)
}
throw error
} Prevention
- Sort samples after merging recordings or input streams
- Keep recording appends chronological in the capture pipeline
- Avoid manual reordering of sample arrays in editors
When it happens
Trigger: Calling parseLive2DMotionRecording on a recording whose samples array has a decreasing atMs somewhere after the first element, from out-of-order appends, merges, or edits.
Common situations: Merging multiple recordings or input streams without sorting; editor drag operations that move a sample earlier without reordering the array; hand-edited JSON.
Related errors
- The motion project source samples are not in time order.
- The motion project overlay points are not in time order.
- The crop range is outside the motion timeline.
- The motion project contains an invalid overlay span.
- The motion project contains an invalid overlay point.
AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-09-02).
Data as JSON: /api/errors/89427f0d5a19c81d.
Report an issue: GitHub.