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

  1. Set source.durationMs equal to the project's top-level durationMs (or vice versa to the true motion length).
  2. Re-export the motion project from the AIRI devtools instead of hand-editing.
  3. 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

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


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