{"record":{"id":"5ccdf143eeab577a","repo":"moeru-ai/airi","slug":"no-vrm-animation-loaded","errorCode":null,"errorMessage":"No VRM animation loaded","messagePattern":"No VRM animation loaded","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/stage-ui-three/src/components/Model/VRMModel.vue","lineNumber":778,"sourceCode":"      camera: camera.value,\n      reason: currentLoadReason,\n      vrm: _vrm,\n      vrmGroup: _vrmGroup,\n    })\n\n    /*\n      * Animation setting\n    */\n    const animation = await loadVRMAnimation(idleAnimation.value)\n    const clip = await clipFromVRMAnimation(_vrm, animation)\n    if (!isLoadRequestCurrent(requestId)) {\n      disposeDetachedVrm(nextVrm, nextVrmGroup)\n      return\n    }\n    if (!clip) {\n      disposeDetachedVrm(nextVrm, nextVrmGroup)\n      emitVrmLoadError(currentLoadReason, loadStartedAt, 'No VRM animation loaded')\n      console.warn('No VRM animation loaded')\n      if (isLoadRequestCurrent(requestId))\n        emit('error', new Error('No VRM animation loaded'))\n      return\n    }\n    // Re-anchor the root position track to the model origin\n    reAnchorRootPositionTrack(clip, _vrm)\n\n    // play animation\n    nextVrmAnimationMixer = new AnimationMixer(_vrm.scene)\n    nextVrmAnimationMixer.clipAction(clip).play()\n\n    nextVrmEmote = useVRMEmote(_vrm)\n\n    /*\n      * Shader setting\n    */\n    const isShaderMat = (m: any): m is ShaderMaterial => !!m?.isShaderMaterial\n","sourceCodeStart":760,"sourceCodeEnd":796,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui-three/src/components/Model/VRMModel.vue#L760-L796","documentation":"After the VRM loads, the component loads the idle animation via loadVRMAnimation(idleAnimation) and converts it with clipFromVRMAnimation. loadVRMAnimation returns undefined when the .vrma file's gltf.userData has no vrmAnimations (the file is not a valid VRMA or contains zero VRM animation entries), so the clip is undefined. The component then disposes the half-loaded VRM, reports the load as failed and emits an 'error' event — the model does not appear.","triggerScenarios":"The idleAnimation URL points at a file that is not a valid .vrma: a plain glb/gltf, a truncated download, an HTML error page served in place of the asset, or a genuine .vrma whose vrmAnimations array is empty.","commonSituations":"Bundled default idle animation missing or corrupted in the deployment; passing a generic glTF animation instead of a VRMA; a build step or CDN dropping/mangling the .vrma asset.","solutions":["Verify the idleAnimation URL actually serves a valid .vrma (check the network tab; it must parse as glTF containing VRM animation extensions)","Re-supply a known-good VRMA idle file (e.g. the bundled idle loop) and reload","Handle the component's 'error' event in the parent to surface the failure instead of a blank scene","If authoring your own file, export at least one VRM animation into the .vrma"],"exampleFix":"// before\nconst animation = await loadVRMAnimation(idleAnimation.value)\nconst clip = await clipFromVRMAnimation(_vrm, animation)\n\n// after\nconst animation = await loadVRMAnimation(idleAnimation.value)\nconst clip = await clipFromVRMAnimation(_vrm, animation)\nif (!clip) {\n  throw new Error(`Idle animation at ${idleAnimation.value} is not a valid .vrma with at least one VRM animation`)\n}","handlingStrategy":"try-catch","validationCode":"// Validate the .vrma before use\nconst gltf = await useVRMLoader().loadAsync(url)\nconst animations = (gltf.userData as GLTFUserdata).vrmAnimations\nif (!animations || animations.length === 0) {\n  throw new Error(`File at ${url} is not a valid .vrma containing VRM animations`)\n}","typeGuard":"function isVRMAUserData(userData: unknown): userData is GLTFUserdata {\n  return Boolean(userData) && typeof userData === 'object'\n    && Array.isArray((userData as GLTFUserdata).vrmAnimations)\n    && (userData as GLTFUserdata).vrmAnimations.length > 0\n}","tryCatchPattern":"try {\n  const animation = await loadVRMAnimation(idleAnimation.value)\n  const clip = await clipFromVRMAnimation(vrm, animation)\n  if (!clip)\n    throw new Error('No VRM animation loaded')\n}\ncatch (error) {\n  // Distinguish asset-invalid from network failure before deciding to refetch or fall back to a bundled idle\n  emit('error', error instanceof Error ? error : new Error(String(error)))\n}","preventionTips":["Serve idle animations only from verified .vrma assets with at least one VRM animation","Check network responses for the .vrma (status 200, glTF content type) before loading","Handle the component's 'error' event so a bad idle animation does not present as a blank scene","Keep a known-good bundled idle VRMA as a fallback source"],"tags":["vrm","vrma","animation","asset-loading","three"],"backgroundTag":"animation-file-invalid","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}