moeru-ai/airi · error · Error
The motion project source is invalid.
Error message
The motion project source is invalid.
What it means
This is an internal-consistency check: the embedded source motion's durationMs must equal the project's top-level durationMs. If they diverge, the project file is considered corrupt or incorrectly assembled, since the cropped project derives its timeline from the source.
Source
Thrown at packages/stage-ui/src/features/devtools/motion/live2d/composables/keyframes.ts:456
}
/** Parses a motion project file and checks its structural and timeline invariants. */
export function parseLive2DMotionProject(raw: string): Live2DMotionProject {
let input: unknown
try {
input = JSON.parse(raw)
}
catch {
throw new Error('The file does not contain valid JSON.')
}
const result = safeParse(motionProjectSchema, input)
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.')
}
}View on GitHub (pinned to 9c213115f8)
Solutions
- Set source.durationMs equal to the project's top-level durationMs (or vice versa to the true motion length).
- Re-export the motion project from the AIRI devtools instead of hand-editing.
- Verify the file was not merged from two different projects.
Example fix
// before
{ "durationMs": 2000, "source": { "durationMs": 1500, "samples": [...] } }
// after
{ "durationMs": 2000, "source": { "durationMs": 2000, "samples": [...] } } Defensive patterns
Strategy: validation
Validate before calling
function hasConsistentDurations(parsed) {
return parsed.source != null
&& typeof parsed.source.durationMs === 'number'
&& typeof parsed.durationMs === 'number'
&& parsed.source.durationMs === parsed.durationMs
} Try / catch
try {
const project = parseLive2DMotionProject(raw)
}
catch (error) {
if (error.message === 'The motion project source is invalid.') {
notifyUser('Project file is inconsistent: source duration does not match project duration. Re-export the file.')
}
else throw error
} Prevention
- Always write source.durationMs and durationMs from the same value at export time.
- Run a pre-import check that these two fields match and warn early.
- Avoid merging fields from different exported projects.
- Re-export rather than manually editing exported files.
When it happens
Trigger: Parsing a project JSON where source.durationMs differs from project.durationMs (e.g. hand-edited durations, partial migration between schema versions, or a file assembled by copying fields from two different projects).
Common situations: Manual editing of exported project files; a buggy external exporter writing mismatched durations; concatenating fields from two motion projects.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- The motion project source timeline is invalid.
- The MAGIC frame must contain ${poseAxes.length} Live2D value
- Archive entry not found: ${filePath}
- The crop range is outside the motion timeline.
- The file does not contain valid JSON.
AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-09-02).
Data as JSON: /api/errors/b63f313134ce28fc.
Report an issue: GitHub.