moeru-ai/airi · error · Error

The MAGIC frame must contain ${poseAxes.length} Live2D value

Error message

The MAGIC frame must contain ${poseAxes.length} Live2D values.

What it means

`poseFromValues()` converts a MAGIC frame (array of numbers) into a Live2D pose using a fixed channel order (`poseAxes`). The input array length must exactly equal the number of pose axes; any other length indicates a protocol/frame mismatch and is rejected to avoid silently mapping wrong indices onto Live2D parameters.

Source

Thrown at packages/model-driver-magic-live2d/src/pose.ts:69

  headZ: 0,
  bodyX: 0,
  bodyY: 0,
  bodyZ: 0,
  mouthForm: 0,
  mouthOpen: 0,
  offsetX: 0,
  offsetY: 0,
})

/** Converts one Live2D pose to the stable MAGIC channel order. */
export function valuesFromPose(pose: Pose): number[] {
  return poseAxes.map(axis => pose[axis])
}

/** Converts one MAGIC frame from the stable channel order to a Live2D pose. */
export function poseFromValues(values: readonly number[]): Pose {
  if (values.length !== poseAxes.length)
    throw new Error(`The MAGIC frame must contain ${poseAxes.length} Live2D values.`)

  const pose = { ...neutralPose }
  for (let index = 0; index < poseAxes.length; index++)
    pose[poseAxes[index]] = values[index]
  return pose
}

/** Converts a fixed-rate Live2D pose sequence to MAGIC training frames. */
export function createTrainingSequence(source: {
  sampleRateHz: number
  sourceDurationMs: number
  poses: readonly Pose[]
}): TrainingSequence {
  return {
    sampleRateHz: source.sampleRateHz,
    sourceDurationMs: source.sourceDurationMs,
    frames: source.poses.map(valuesFromPose),
  }

View on GitHub (pinned to 9c213115f8)

Solutions

  1. Log `values.length` and compare against the expected `poseAxes.length` to find which side produced the wrong dimensionality.
  2. Update the MAGIC frame producer so it emits exactly the pose axis count expected by this driver.
  3. If versions differ, align both sides on the same channel order/count before streaming frames.
  4. Validate frame length at the ingestion boundary and drop/pad malformed frames before calling `poseFromValues`.

Example fix

// before
const pose = poseFromValues(frame.values)
// after
if (frame.values.length !== EXPECTED_POSE_AXES)
  throw new Error(`Bad frame length ${frame.values.length}`)
const pose = poseFromValues(frame.values)
Defensive patterns

Strategy: validation

Validate before calling

function isValidMagicFrame(values: readonly number[], expected: number): boolean {
  return Array.isArray(values) && values.length === expected
}

Type guard

function isMagicFrame(values: unknown, axisCount: number): values is number[] {
  return Array.isArray(values) && values.length === axisCount && values.every(v => typeof v === 'number' && Number.isFinite(v))
}

Try / catch

try {
  const pose = poseFromValues(frame)
} catch (error) {
  if (error instanceof Error && error.message.includes('Live2D values')) {
    console.error(`Frame length mismatch: got ${frame.length}`)
  } else {
    throw error
  }
}

Prevention

When it happens

Trigger: Passing a frame array with fewer or more values than `poseAxes.length` — e.g. a truncated network frame, an emitter configured with a different axis subset, or feeding raw model outputs whose dimensionality was changed without updating the pose channel list.

Common situations: Changing the MAGIC model output dimension (adding/removing channels) without updating the driver; a sender/receiver version mismatch producing 3-axis frames into a 4-axis pipeline; slicing or padding frames incorrectly before handing them to the driver.

Related errors


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