moeru-ai/airi · warning

No VRM animations found in the .vrma file

Error message

No VRM animations found in the .vrma file

What it means

loadVRMAnimation() loads a .vrma file through the GLTF loader with pixiv's VRM animation plugin; the plugin writes parsed clips into gltf.userData.vrmAnimations only when the glTF carries the VRMC_vrm_animation extension. This warn fires when the property is entirely absent: the file was fetched and parsed as glTF JSON, but the loader never recognized it as a VRM animation. The function returns undefined, so downstream code must tolerate that.

Source

Thrown at packages/stage-ui-three/src/composables/vrm/animation.ts:26

import { randFloat } from 'three/src/math/MathUtils.js'
import { ref } from 'vue'

import { useVRMLoader } from './loader'
import { randomSaccadeInterval } from './utils/eye-motions'

export interface GLTFUserdata extends Record<string, any> {
  vrmAnimations: VRMAnimation[]
}

export async function loadVRMAnimation(url: string) {
  const loader = useVRMLoader()

  // load VRM Animation .vrma file
  const gltf = await loader.loadAsync(url)

  const userData = gltf.userData as GLTFUserdata
  if (!userData.vrmAnimations) {
    console.warn('No VRM animations found in the .vrma file')
    return
  }
  if (userData.vrmAnimations.length === 0) {
    console.warn('No VRM animations found in the .vrma file')
    return
  }

  return userData.vrmAnimations[0]
}

export async function clipFromVRMAnimation(vrm?: VRMCore, animation?: VRMAnimation) {
  if (!vrm) {
    console.warn('No VRM found')
    return
  }
  if (!animation) {
    return
  }

View on GitHub (pinned to 677329427f)

Solutions

  1. Open the URL directly and confirm the body is a real .vrma glTF with "extensions" containing VRMC_vrm_animation.
  2. Verify useVRMLoader registers the VRM animation plugin on the GLTFLoader used by loadAsync.
  3. Upgrade @pixiv/three-vrm / @pixiv/three-vrm-core to a release that supports the VRMA spec version of your file.
  4. Handle the undefined return so UI does not silently keep a broken animation state.

Example fix

// before
const anim = await loadVRMAnimation(url) // may be undefined, warns

// after
const anim = await loadVRMAnimation(url)
if (!anim) {
  // fetch and inspect the file; surface a user-visible error
  throw new Error(`File at ${url} is not a valid .vrma (no VRMC_vrm_animation extension)`)
}
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetch(url)
const json = await res.json().catch(() => null)
const isVrma = !!json?.extensionsUsed?.includes?.('VRMC_vrm_animation')
  || !!json?.extensions?.VRMC_vrm_animation
if (!isVrma) throw new Error('Not a .vrma file')

Type guard

function hasVrmAnimations(gltf: unknown): gltf is { userData: { vrmAnimations: unknown[] } } {
  return Array.isArray((gltf as { userData?: { vrmAnimations?: unknown[] } })?.userData?.vrmAnimations)
}

Try / catch

try {
  const anim = await loadVRMAnimation(url)
  if (!anim) return // warned inside; degrade to no idle animation
  const clip = await clipFromVRMAnimation(vrm, anim)
} catch (err) {
  console.error('vrma load failed', errorMessageFrom(err))
}

Prevention

When it happens

Trigger: Passing a URL that resolves to a .vrm model or generic glTF instead of a .vrma; the server returning a 200 JSON error page; the GLTFLoader being created without the VRM animation plugin registered (useVRMLoader misconfigured); a three-vrm version that predates VRMA support.

Common situations: Wrong/moved asset URL behind a CDN or static host that serves a JSON body with 200; upgrading @pixiv/three-vrm and the plugin registration code drifting; hand-authored .vrma files missing the extensions block.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/59b20c43dc2f849a. Report an issue: GitHub.