{"record":{"id":"9b33824d5389574b","repo":"moeru-ai/airi","slug":"emotion-emotionname-not-found","errorCode":null,"errorMessage":"Emotion ${emotionName} not found","messagePattern":"Emotion (.+?) not found","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui-three/src/composables/vrm/expression.ts","lineNumber":100,"sourceCode":"      expression: [\n        { name: 'relaxed', value: 0.7 },\n      ],\n      blendDuration: 0.4,\n    }],\n  ])\n\n  const clearResetTimeout = () => {\n    if (resetTimeout.value) {\n      clearTimeout(resetTimeout.value)\n      resetTimeout.value = undefined\n    }\n  }\n\n  const setEmotion = (emotionName: string, intensity = 1) => {\n    clearResetTimeout()\n\n    if (!emotionStates.has(emotionName)) {\n      console.warn(`Emotion ${emotionName} not found`)\n      return\n    }\n\n    const emotionState = emotionStates.get(emotionName)!\n    currentEmotion.value = emotionName\n    isTransitioning.value = true\n    transitionProgress.value = 0\n\n    // Store current expression values as starting point BEFORE resetting,\n    // so the lerp transition starts from the actual displayed values\n    // instead of snapping to 0 first (fixes #590).\n    currentExpressionValues.value.clear()\n    targetExpressionValues.value.clear()\n\n    const normalizedIntensity = clampIntensity(intensity)\n\n    if (vrm.expressionManager) {\n      // Capture current values for all expressions we'll be transitioning","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui-three/src/composables/vrm/expression.ts#L82-L118","documentation":"useVRMEmote(vrm).setEmotion() looks up emotionName in a local emotionStates Map that defines exactly: happy, sad, angry, surprised, neutral, think, relaxed. Unknown names warn and return — no expression change, no transition. Note the VRM table is intentionally narrower than the shared Emotion enum (no curious/question/awkward), so valid upstream emotions can still miss here.","triggerScenarios":"Forwarding Emotion enum values like 'curious', 'question', or 'awkward' straight from the emotions queue to setEmotion; passing arbitrary LLM strings without normalization; typos ('surprise' instead of 'surprised').","commonSituations":"Shared emotion vocabulary grows but the VRM emote table is not extended; feeding raw ACT payload names into the renderer; a model lacking 'relaxed' custom expressions in a forked table.","solutions":["Map emotion names through EMOTION_VRMExpressionName_value (packages/stage-ui/src/constants/emotions.ts) before calling setEmotion.","Add the missing state to the emotionStates Map in packages/stage-ui-three/src/composables/vrm/expression.ts.","Normalize/validate names at the boundary (queues.ts normalizeEmotionName pattern) so only supported keys reach the renderer."],"exampleFix":"// before\nemote.setEmotion(emotionName) // 'curious' warns: not in emotionStates\n\n// after\nconst VRM_EMOTIONS = new Set(['happy', 'sad', 'angry', 'surprised', 'neutral', 'think', 'relaxed'])\nemote.setEmotion(VRM_EMOTIONS.has(emotionName) ? emotionName : 'neutral')","handlingStrategy":"type-guard","validationCode":"const VRM_EMOTIONS = new Set(['happy', 'sad', 'angry', 'surprised', 'neutral', 'think', 'relaxed'])\nif (!VRM_EMOTIONS.has(name)) name = 'neutral'","typeGuard":"function isVRMEmotion(name: string): boolean {\n  return ['happy', 'sad', 'angry', 'surprised', 'neutral', 'think', 'relaxed'].includes(name)\n}","tryCatchPattern":null,"preventionTips":["Expose the supported set from the emote composable instead of duplicating it at call sites.","Map shared Emotion values through EMOTION_VRMExpressionName_value before calling setEmotion.","Extend emotionStates and the shared enum together in one change."],"tags":["vrm","emotion","expression","rendering"],"backgroundTag":"unknown-emotion-name","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"}