moeru-ai/airi · error · Error
The motion project contains an invalid overlay point.
Error message
The motion project contains an invalid overlay point.
What it means
parseLive2DMotionProject requires every overlay point's atMs to lie within the overlay's own span [startMs, endMs]. Points outside the span cannot be interpolated correctly and indicate corrupt or misplaced data. This error is thrown when any overlay point's atMs is less than startMs or greater than endMs.
Source
Thrown at packages/stage-ui/src/features/devtools/motion/live2d/composables/keyframes.ts:469
if (!result.success)
throw new Error('The file is not an AIRI Live2D motion project.')
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
- Clamp each point.atMs to [overlay.startMs, overlay.endMs] before parsing
- Recompute or move points whenever an overlay span changes
- Regenerate the overlay from its source data if points and span disagree
Example fix
// before
overlay.points = importedPoints
// after
overlay.points = importedPoints.map(p => ({ ...p, atMs: Math.min(Math.max(p.atMs, overlay.startMs), overlay.endMs) })) Defensive patterns
Strategy: validation
Validate before calling
for (const overlay of project.overlays) {
for (const point of overlay.points)
point.atMs = Math.min(Math.max(point.atMs, overlay.startMs), overlay.endMs)
} Type guard
const pointsWithinSpan = (o) => o.points.every(p => p.atMs >= o.startMs && p.atMs <= o.endMs)
Try / catch
try {
parseLive2DMotionProject(project)
}
catch (error) {
if (error.message.includes('invalid overlay point'))
console.error('An overlay point lies outside its span; clamp point.atMs to [startMs, endMs]')
throw error
} Prevention
- Re-clamp all points whenever an overlay span is resized
- Move points and spans together in editing UIs
- Validate imported overlay data before persistence
When it happens
Trigger: Calling parseLive2DMotionProject with an overlay whose points contain atMs values outside its [startMs, endMs] window, typically after editing the span or moving points independently.
Common situations: Narrowing an overlay's span after points were placed; drag-editing UIs that update points before spans; programmatically shifting overlay spans without re-clamping point timestamps; imported motion data with mismatched units.
Related errors
- The motion project contains an invalid overlay span.
- The crop range is outside the motion timeline.
- The motion project source samples are not in time order.
- The motion project overlay points are not in time order.
- The first motion sample must start at 0 ms.
AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-09-02).
Data as JSON: /api/errors/8680a70033642849.
Report an issue: GitHub.