moeru-ai/airi · warning

[mmd] motion file "${descriptor.name}" (${descriptor.id}) no

Error message

[mmd] motion file "${descriptor.name}" (${descriptor.id}) not found in storage

What it means

During syncMotions(), the MMD scene iterates availableMotions descriptors and fetches each VMD blob from IndexedDB via mmdStore.getMotionFile(descriptor.id). A descriptor whose blob is missing means the motion list and the blob store are out of sync; that motion is skipped with this warning and sync continues.

Source

Thrown at packages/stage-ui-mmd/src/components/scenes/MMD.vue:329

/**
 * Loads and registers any imported VMD motions not yet bound to the current
 * model, then (re)applies the selected idle motion. Safe to call repeatedly;
 * already-registered motions are skipped.
 */
async function syncMotions() {
  if (!animation || !mesh)
    return

  for (const descriptor of availableMotions.value) {
    if (registeredMotions.has(descriptor.name))
      continue
    try {
      // The VMD file lives in IndexedDB (shared across windows); build a
      // window-local object URL to load it, then revoke it once parsed.
      const file = await mmdStore.getMotionFile(descriptor.id)
      if (!file) {
        console.warn(`[mmd] motion file "${descriptor.name}" (${descriptor.id}) not found in storage`)
        continue
      }
      const url = URL.createObjectURL(file)
      try {
        const clip = await loadMMDAnimationClip(url, mesh)
        animation.registerClip(descriptor.name, clip)
        registeredMotions.add(descriptor.name)
        if (clip.tracks.length === 0) {
          console.warn(
            `[mmd] motion "${descriptor.name}" loaded but has 0 tracks matching this model. `
            + 'The VMD\'s bone/morph names likely do not match the model (different rig/naming).',
          )
        }
      }
      finally {
        URL.revokeObjectURL(url)
      }
    }

View on GitHub (pinned to 677329427f)

Solutions

  1. Re-import the missing VMD motion file so the blob exists again for that descriptor
  2. Delete the stale motion entry from the MMD settings list so descriptors match storage
  3. If it recurs across motions, clear the MMD store and re-import to rebuild a consistent state
  4. Request storage persistence (navigator.storage.persist()) so IndexedDB is not evicted under quota pressure
Defensive patterns

Strategy: validation

Validate before calling

// Before registering a motion descriptor
const file = await mmdStore.getMotionFile(descriptor.id)
if (!file) {
  console.warn(`[mmd] motion file "${descriptor.name}" (${descriptor.id}) not found in storage`)
  await mmdStore.removeMotion(descriptor.id) // prune the stale descriptor
  continue
}

Type guard

async function hasMotionFile(descriptor: MotionDescriptor): Promise<boolean> {
  return (await mmdStore.getMotionFile(descriptor.id)) !== undefined
}

Prevention

When it happens

Trigger: availableMotions contains an id whose VMD file is gone from IndexedDB: browser site data cleared or quota-evicted while descriptors persisted elsewhere, a deletion performed in another window (IndexedDB is shared across windows) leaving a stale descriptor, or a storage migration that dropped files but kept descriptors.

Common situations: User cleared browsing data or hit storage quota eviction; two app windows open where one deletes a motion; an import interrupted between writing the descriptor and writing the blob.

Related errors


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