moeru-ai/airi · error · Error
The motion project overlay points are not in time order.
Error message
The motion project overlay points are not in time order.
What it means
parseLive2DMotionProject requires overlay points to be sorted by atMs in non-decreasing order, matching the same invariant enforced on source samples. This error is thrown when consecutive overlay points have decreasing atMs values.
Source
Thrown at packages/stage-ui/src/features/devtools/motion/live2d/composables/keyframes.ts:472
const project = result.output
if (project.source.durationMs !== project.durationMs)
throw new Error('The motion project source is invalid.')
if (project.source.samples[0].atMs !== 0 || project.source.samples.at(-1)!.atMs > project.durationMs)
throw new Error('The motion project source timeline is invalid.')
for (let index = 1; index < project.source.samples.length; index++) {
if (project.source.samples[index].atMs < project.source.samples[index - 1].atMs)
throw new Error('The motion project source samples are not in time order.')
}
for (const overlay of project.overlays) {
if (overlay.endMs > project.durationMs || overlay.startMs > overlay.endMs)
throw new Error('The motion project contains an invalid overlay span.')
if (overlay.points.some(point => point.atMs < overlay.startMs || point.atMs > overlay.endMs))
throw new Error('The motion project contains an invalid overlay point.')
for (let index = 1; index < overlay.points.length; index++) {
if (overlay.points[index].atMs < overlay.points[index - 1].atMs)
throw new Error('The motion project overlay points are not in time order.')
}
}
return structuredClone(project)
}
View on GitHub (pinned to 9c213115f8)
Solutions
- Sort overlay.points by atMs ascending before calling parseLive2DMotionProject
- Fix the overlay editing code to keep points ordered on insert/move
- Reject or re-sort imported point data during ingest
Example fix
// before parseLive2DMotionProject(project) // after project.overlays.forEach(o => o.points.sort((a, b) => a.atMs - b.atMs)) parseLive2DMotionProject(project)
Defensive patterns
Strategy: validation
Validate before calling
project.overlays.forEach(o => o.points.sort((a, b) => a.atMs - b.atMs))
Type guard
const isSortedByAtMs = (items) => items.every((p, i) => i === 0 || p.atMs >= items[i - 1].atMs)
Try / catch
try {
parseLive2DMotionProject(project)
}
catch (error) {
if (error.message.includes('overlay points are not in time order')) {
project.overlays.forEach(o => o.points.sort((a, b) => a.atMs - b.atMs))
parseLive2DMotionProject(project)
}
else throw error
} Prevention
- Sort overlay points after any insert or drag-move operation
- Use an insertion helper that places points by atMs instead of push
- Add regression tests for point reordering flows
When it happens
Trigger: Calling parseLive2DMotionProject where an overlay's points array has atMs[i] < atMs[i-1], e.g. points inserted at the front, interleaved from multiple sources, or manually reordered.
Common situations: UI drag interactions that move a point earlier than its predecessor; merging keyframes from two recording passes; hand-edited JSON with reordered entries.
Related errors
- The motion project source samples are not in time order.
- The motion samples must be 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/699801099ebadf89.
Report an issue: GitHub.