moeru-ai/airi · warning
Cannot set motion: model not loaded
Error message
Cannot set motion: model not loaded
What it means
setMotion() in the Live2D Model component requires a fully constructed Live2DModel instance in model.value. If a motion is requested before loadModel() finished (or after it bailed on a missing src or a load failure), the guard logs this warning and returns without throwing — the motion request is dropped.
Source
Thrown at packages/stage-ui-live2d/src/components/scenes/live2d/Model.vue:491
// Build a function that can read exp3 files relative to the model root.
// For URL-loaded models, resolveURL gives us the full URL. For ZIP-loaded
// models the resolved URL points to an in-memory blob/object URL.
const readExpFile = async (filePath: string): Promise<string> => {
const resolvedUrl: string = settings.resolveURL?.(filePath) ?? filePath
const response = await fetch(resolvedUrl)
if (!response.ok)
throw new Error(`Failed to fetch exp3 file: ${filePath} (${response.status})`)
return response.text()
}
await expressionController.initialise(expressionRefs, readExpFile)
}
async function setMotion(motionName: string, index?: number) {
// TODO: motion? Not every Live2D model has motion, we do need to help users to set motion
if (!model.value) {
console.warn('Cannot set motion: model not loaded')
return
}
console.info('Setting motion:', motionName, 'index:', index)
try {
await model.value.motion(motionName, index, MotionPriority.FORCE)
console.info('Motion started successfully:', motionName)
}
catch (error) {
console.error('Failed to start motion:', motionName, error)
}
}
const dropShadowColorComputer = ref<HTMLDivElement>()
const dropShadowAnimationId = ref(0)
function updateDropShadowFilter() {
if (!model.value)View on GitHub (pinned to 677329427f)
Solutions
- Only issue motions after the component reports the model is loaded (watch its exposed state or a load event)
- Queue motion requests and flush the queue once model.value exists
- Verify a modelSrc is actually set — without it the model never loads and every setMotion warns
Example fix
// before
onMounted(() => modelRef.value?.setMotion('greeting'))
// after
watch(
() => modelRef.value?.componentState,
(state) => {
if (state === 'ready' || state === 'mounted')
modelRef.value?.setMotion('greeting')
},
) Defensive patterns
Strategy: type-guard
Validate before calling
// Before requesting a motion
if (!modelRef.value?.model) {
pendingMotions.push({ name: motionName, index })
}
else {
modelRef.value.setMotion(motionName, index)
} Type guard
// Inside the component, expose a readiness check
function isModelLoaded(): boolean {
return model.value !== undefined && componentState.value === 'mounted'
} Prevention
- Wait for the component's loaded state before issuing motions
- Queue motion requests that arrive during load and flush them on ready
- Do not call setMotion after destroying the model during a model switch
When it happens
Trigger: Calling the exposed setMotion (or dispatching a motion event that reaches it) while model.value is undefined: during initial load, right after modelSrc changes (old model destroyed, new one loading), or when no modelSrc was provided so loadModel returned early.
Common situations: Parent invokes setMotion in its own onMounted without waiting for the model's ready state; an LLM-driven message triggers a motion before the model finishes loading; motions queued for a previous model fire during a model switch.
Related errors
- No Live2D model source provided.
- The crop range is outside the motion timeline.
- The motion project source samples are not in time order.
- The motion project contains an invalid overlay span.
- The motion project contains an invalid overlay point.
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/831ea758ef655095.
Report an issue: GitHub.