moeru-ai/airi · warning
[mmd] playAction skipped: "${name}" is not registered
Error message
[mmd] playAction skipped: "${name}" is not registered What it means
The MMD animation manager keeps clips in a Map populated by registerClip(name, clip). playAction(name) looks the name up; when no clip is registered under it, it warns and returns false instead of throwing — the current action is left untouched (idle keeps playing).
Source
Thrown at packages/stage-ui-mmd/src/composables/mmd/animation-manager.ts:148
}
if (currentAction && currentAction !== idleAction)
currentAction.fadeOut(crossfade)
// A one-shot may reuse the same action, so restore its looping contract.
idleAction.reset().setLoop(LoopRepeat, Number.POSITIVE_INFINITY).setEffectiveWeight(1).fadeIn(crossfade).play()
currentAction = idleAction
}
/**
* Plays a registered motion and cross-fades from the current action.
* One-shots return to idle; looping actions remain active until replaced.
*
* @returns `false` when no clip is registered under `name`.
*/
function playAction(name: string, actionOptions: PlayActionOptions = {}): boolean {
const clip = registry.get(name)
if (!clip) {
console.warn(`[mmd] playAction skipped: "${name}" is not registered`)
return false
}
const loop = actionOptions.loop ?? false
const crossfade = actionOptions.crossfade ?? DEFAULT_CROSSFADE
const action = mixer.clipAction(clip)
action.reset()
action.setLoop(loop ? LoopRepeat : LoopOnce, loop ? Number.POSITIVE_INFINITY : 1)
action.clampWhenFinished = !loop
action.setEffectiveWeight(1)
action.fadeIn(crossfade).play()
if (currentAction && currentAction !== action) {
removeFinishListener(currentAction)
currentAction.fadeOut(crossfade)
}
currentAction = action
View on GitHub (pinned to 677329427f)
Solutions
- Register the clip with registerClip(name, clip) before calling playAction
- Check the boolean return value and fall back (keep idle or try a default motion) instead of assuming playback started
- Log availableClips() when the miss happens to catch typos and case mismatches against the real registry keys
Example fix
// before
animation.playAction('Wave') // registry has 'wave' -> skipped, returns false
// after
if (!animation.playAction('Wave'))
animation.playAction(animation.availableClips().find(c => c.toLowerCase() === 'wave') ?? 'idle') Defensive patterns
Strategy: validation
Validate before calling
if (!animation.availableClips().includes(name)) {
console.warn(`motion ${name} not registered, have:`, animation.availableClips().join(', '))
return
}
animation.playAction(name) Type guard
function isRegisteredMotion(manager: { availableClips(): string[] }, name: string): name is string {
return manager.availableClips().includes(name)
} Prevention
- Register all clips before exposing playback triggers
- Always branch on the boolean return of playAction
- Validate persisted motion-name settings against availableClips() on load
When it happens
Trigger: Calling playAction with a name never passed to registerClip: typo, case mismatch, a motion file that failed to import, or calling playAction before clip registration finished (e.g. before the VMD import promise resolved).
Common situations: Hardcoded motion names that don't match VMD-derived names; user-configurable motion mappings pointing at files that weren't loaded; race between model load and an autoplay trigger.
Related errors
- [mmd] setIdleMotion skipped: "${name}" is not registered
- No Hips.position track of type VectorKeyframeTrack found in
- [mmd] motion "${descriptor.name}" loaded but has 0 tracks ma
- Tamagotchi extension tool not found: ${key}
- Module `${moduleId}` was not found.
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/2c49be3ffbad631c.
Report an issue: GitHub.