{"record":{"id":"4d5f488ed082c697","repo":"moeru-ai/airi","slug":"the-magic-frame-must-contain-poseaxes-length-li","errorCode":null,"errorMessage":"The MAGIC frame must contain ${poseAxes.length} Live2D values.","messagePattern":"The MAGIC frame must contain (.+?) Live2D values\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/model-driver-magic-live2d/src/pose.ts","lineNumber":69,"sourceCode":"  headZ: 0,\n  bodyX: 0,\n  bodyY: 0,\n  bodyZ: 0,\n  mouthForm: 0,\n  mouthOpen: 0,\n  offsetX: 0,\n  offsetY: 0,\n})\n\n/** Converts one Live2D pose to the stable MAGIC channel order. */\nexport function valuesFromPose(pose: Pose): number[] {\n  return poseAxes.map(axis => pose[axis])\n}\n\n/** Converts one MAGIC frame from the stable channel order to a Live2D pose. */\nexport function poseFromValues(values: readonly number[]): Pose {\n  if (values.length !== poseAxes.length)\n    throw new Error(`The MAGIC frame must contain ${poseAxes.length} Live2D values.`)\n\n  const pose = { ...neutralPose }\n  for (let index = 0; index < poseAxes.length; index++)\n    pose[poseAxes[index]] = values[index]\n  return pose\n}\n\n/** Converts a fixed-rate Live2D pose sequence to MAGIC training frames. */\nexport function createTrainingSequence(source: {\n  sampleRateHz: number\n  sourceDurationMs: number\n  poses: readonly Pose[]\n}): TrainingSequence {\n  return {\n    sampleRateHz: source.sampleRateHz,\n    sourceDurationMs: source.sourceDurationMs,\n    frames: source.poses.map(valuesFromPose),\n  }","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/moeru-ai/airi/blob/9c213115f8bd0fff9e6eabab02b077ac32da21be/packages/model-driver-magic-live2d/src/pose.ts#L51-L87","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Log `values.length` and compare against the expected `poseAxes.length` to find which side produced the wrong dimensionality.","Update the MAGIC frame producer so it emits exactly the pose axis count expected by this driver.","If versions differ, align both sides on the same channel order/count before streaming frames.","Validate frame length at the ingestion boundary and drop/pad malformed frames before calling `poseFromValues`."],"exampleFix":"// before\nconst pose = poseFromValues(frame.values)\n// after\nif (frame.values.length !== EXPECTED_POSE_AXES)\n  throw new Error(`Bad frame length ${frame.values.length}`)\nconst pose = poseFromValues(frame.values)","handlingStrategy":"validation","validationCode":"function isValidMagicFrame(values: readonly number[], expected: number): boolean {\n  return Array.isArray(values) && values.length === expected\n}","typeGuard":"function isMagicFrame(values: unknown, axisCount: number): values is number[] {\n  return Array.isArray(values) && values.length === axisCount && values.every(v => typeof v === 'number' && Number.isFinite(v))\n}","tryCatchPattern":"try {\n  const pose = poseFromValues(frame)\n} catch (error) {\n  if (error instanceof Error && error.message.includes('Live2D values')) {\n    console.error(`Frame length mismatch: got ${frame.length}`)\n  } else {\n    throw error\n  }\n}","preventionTips":["Keep the MAGIC emitter and this driver on the same channel-order/version.","Validate frame length at the network/IPC boundary before the pose conversion.","Log both lengths (got vs expected) on mismatch for quick diagnosis.","Pin a protocol version between sender and receiver."],"tags":["validation","dimension-mismatch","live2d","protocol"],"backgroundTag":"frame-length-mismatch","analyzedSha":"9c213115f8bd0fff9e6eabab02b077ac32da21be","analyzedAt":"2026-09-02T04:27:24.639Z","contentChangedAt":"2026-09-02T04:27:24.639Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}