moeru-ai/airi · warning
[mmd] emotion ${emotion} not found
Error message
[mmd] emotion ${emotion} not found What it means
useMMDEmote().setEmotion() maps an emotion name to MMD morph influences via the EMOTION_MORPHS table (packages/stage-ui-mmd/src/constants/morphs.ts). When the passed Emotion key has no entry in that table, the function warns and returns without starting a transition, so the model's face stays in its previous state. This is a graceful-degradation guard, not a crash: TypeScript normally prevents bad keys, but the value often arrives from untrusted LLM output at runtime.
Source
Thrown at packages/stage-ui-mmd/src/composables/mmd/expression.ts:56
const isTransitioning = ref(false)
const transitionProgress = ref(0)
const startWeights = new Map<MorphSlot, number>()
const targetWeights = new Map<MorphSlot, number>()
let resetTimeout: ReturnType<typeof setTimeout> | undefined
function clearResetTimeout() {
if (resetTimeout) {
clearTimeout(resetTimeout)
resetTimeout = undefined
}
}
function setEmotion(emotion: Emotion, intensity = 1) {
clearResetTimeout()
const state = EMOTION_MORPHS[emotion]
if (!state) {
console.warn(`[mmd] emotion ${emotion} not found`)
return
}
currentEmotion.value = emotion
isTransitioning.value = true
transitionProgress.value = 0
startWeights.clear()
targetWeights.clear()
const normalized = clampIntensity(intensity)
// Capture where each expression slot currently sits so the cross-fade
// starts from the live value instead of snapping to zero first.
for (const slot of EXPRESSION_SLOTS) {
startWeights.set(slot, morphs.get(slot))
targetWeights.set(slot, 0)
}
View on GitHub (pinned to 677329427f)
Solutions
- Check which Emotion keys EMOTION_MORPHS actually defines in packages/stage-ui-mmd/src/constants/morphs.ts and confirm the emotion you send is among them.
- Filter/normalize emotion names at the boundary (as queues.ts normalizeEmotionName does) so only mapped emotions reach setEmotion.
- Add an EMOTION_MORPHS entry mapping the missing emotion to available morph slots (smile/anger/sad/surprise/troubled/serious).
- Fall back to a close mapped emotion (e.g. 'neutral') before calling setEmotion.
Example fix
// before
emote.setEmotion(rawName as Emotion) // warns when unmapped
// after
import { EMOTION_MORPHS } from '../../constants/morphs'
if (rawName in EMOTION_MORPHS) {
emote.setEmotion(rawName as Emotion, intensity)
}
else {
emote.setEmotion(Emotion.Neutral, intensity)
} Defensive patterns
Strategy: type-guard
Validate before calling
import { EMOTION_MORPHS } from '../constants/morphs'
const supported = Object.keys(EMOTION_MORPHS)
if (!supported.includes(name)) name = 'neutral' Type guard
function isMappedMmdEmotion(name: string): name is Emotion {
return Object.prototype.hasOwnProperty.call(EMOTION_MORPHS, name)
} Prevention
- Never cast arbitrary strings to Emotion; normalize with a whitelist first (see normalizeEmotionName in queues.ts).
- When adding an Emotion enum value, add the EMOTION_MORPHS entry in the same change.
- Centralize emotion vocabulary in packages/stage-ui/src/constants/emotions.ts so renderers and queues share one list.
When it happens
Trigger: An ACT emotion payload from the agent/LLM resolves to an Emotion enum value (e.g. 'curious', 'question', 'awkward') that has no morph mapping in EMOTION_MORPHS for the loaded MMD model, and the emotions queue forwards it to useMMDEmote().setEmotion(). Calling setEmotion('relaxed' as Emotion) directly with a key outside the table also triggers it.
Common situations: Adding a new value to the shared Emotion enum (packages/stage-ui/src/constants/emotions.ts) without adding a matching EMOTION_MORPHS entry; MMD models whose morph sets only cover a subset of emotions; casting a raw string to Emotion to bypass the compiler.
Related errors
- Emotion ${emotionName} not found
- [mmd] no vowel mouth morphs (あ/い/う/え/お) resolved; lip-sync c
- MMD ZIP must contain a .pmx or .pmd model file
- [mmd] playAction skipped: "${name}" is not registered
- [mmd] setIdleMotion skipped: "${name}" is not registered
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/a9753bfb2aa56b53.
Report an issue: GitHub.