{"record":{"id":"adc5201844df860d","repo":"moeru-ai/airi","slug":"no-live2d-model-source-provided","errorCode":null,"errorMessage":"No Live2D model source provided.","messagePattern":"No Live2D model source provided\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui-live2d/src/components/scenes/live2d/Model.vue","lineNumber":240,"sourceCode":"  }\n\n  // REVIEW: here as await until(...) guarded the pixiApp and stage to be valid.\n  if (model.value && pixiApp.value?.stage) {\n    // Dispose expression controller before destroying the old model\n    expressionController.dispose()\n    internalModelRef.value = undefined\n\n    try {\n      pixiApp.value.stage.removeChild(model.value)\n      model.value.destroy()\n    }\n    catch (error) {\n      console.warn('Error removing old model:', error)\n    }\n    model.value = undefined\n  }\n  if (!modelSrcRef.value) {\n    console.warn('No Live2D model source provided.')\n    modelLoading.value = false\n    componentState.value = 'mounted'\n    return\n  }\n\n  try {\n    if (isUnmounted) {\n      modelLoading.value = false\n      componentState.value = 'mounted'\n      return\n    }\n\n    const live2DModel = new Live2DModel<PixiLive2DInternalModel>()\n    await Live2DFactory.setupLive2DModel(live2DModel, { url: modelSrcRef.value, id: props.modelId }, { autoInteract: false })\n    availableMotions.value.forEach((motion) => {\n      if (motion.motionName in Emotion) {\n        motionMap.value[motion.fileName] = motion.motionName\n      }","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui-live2d/src/components/scenes/live2d/Model.vue#L222-L258","documentation":"Live2D Model.vue runs loadModel() immediately via watch(modelSrcRef, ..., { immediate: true }). When the optional modelSrc prop is empty there is nothing to load; the component logs this warning, clears modelLoading, sets componentState to 'mounted' and returns instead of throwing. It is a controlled no-op for an unconfigured scene.","triggerScenarios":"Rendering <Model /> from stage-ui-live2d without the modelSrc prop, or binding modelSrc to a reactive value that is still undefined/'' at mount time (settings store not hydrated yet, wrong store path, model deleted).","commonSituations":"First-run/onboarding state where no Live2D model has been imported or selected yet; passing only modelId and expecting the component to resolve the source itself; the source arriving asynchronously after mount.","solutions":["Bind a real source once available: <Model :model-src=\"live2dStore.modelSrc\" :model-id=\"modelId\" />","Guard rendering with v-if=\"modelSrc\" so the component only mounts when a source exists, showing a placeholder otherwise","If the src loads asynchronously, delay mounting until it resolves instead of relying on the watcher to re-run"],"exampleFix":"// before\n<Model :model-id=\"modelId\" />\n\n// after\n<Model v-if=\"modelSrc\" :model-src=\"modelSrc\" :model-id=\"modelId\" />","handlingStrategy":"validation","validationCode":"// Before rendering the Live2D model component\nconst ready = computed(() => typeof modelSrc.value === 'string' && modelSrc.value.length > 0)\n// template: <Model v-if=\"ready\" :model-src=\"modelSrc\" />","typeGuard":"function isModelSource(value: unknown): value is string {\n  return typeof value === 'string' && value.trim().length > 0\n}","tryCatchPattern":null,"preventionTips":["Treat modelSrc as required in practice: never mount the Model without it","Gate the component with v-if on a resolved source and show an empty/placeholder state otherwise","For async sources, await the settings/model store before entering the scene"],"tags":["live2d","props","vue","model-loading"],"backgroundTag":"missing-required-argument","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"}