{"record":{"id":"31aa5f442108f52b","repo":"moeru-ai/airi","slug":"settings-file-not-found","errorCode":null,"errorMessage":"Settings file not found","messagePattern":"Settings file not found","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts","lineNumber":224,"sourceCode":"\nZipLoader.readText = async (jsZip: JSZip, path: string) => {\n  const file = jsZip.file(path)\n\n  if (!file) {\n    throw new Error(`Cannot find file: ${path}`)\n  }\n\n  const text = await file.async('text')\n\n  return isSettingsFile(path) ? sanitizeModelSettingsText(text) : text\n}\n\nconst defaultFileLoaderReadText = FileLoader.readText\nFileLoader.createSettings = async (files: File[]) => {\n  const settingsFile = files.find(file => isSettingsFile(file.webkitRelativePath || file.name))\n\n  if (!settingsFile) {\n    throw new TypeError('Settings file not found')\n  }\n\n  const settingsUrl = settingsFile.webkitRelativePath || settingsFile.name\n  const settingsText = await FileLoader.readText(settingsFile)\n  const settings = createModelSettings(settingsText, settingsUrl)\n  Object.assign(settings, { _objectURL: URL.createObjectURL(settingsFile) })\n\n  return settings\n}\n\nFileLoader.readText = async (file: File) => {\n  const text = await defaultFileLoaderReadText(file)\n  const path = file.webkitRelativePath || file.name\n\n  return isSettingsFile(path) ? sanitizeModelSettingsText(text) : text\n}\n\nZipLoader.getFilePaths = (jsZip: JSZip) => {","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/moeru-ai/airi/blob/9c213115f8bd0fff9e6eabab02b077ac32da21be/packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts#L206-L242","documentation":"Thrown as a TypeError by the FileLoader.createSettings override (live2d-zip-loader) when none of the uploaded File objects matches isSettingsFile — i.e. no file whose webkitRelativePath or name ends in .model3.json or .model.json (excluding ignored entries and items_pinned_to_model.json). The upload path requires a settings file to bootstrap model creation; fake settings from a bare moc are not attempted here.","triggerScenarios":"Calling FileLoader.createSettings with a folder upload lacking any .model3.json/.model.json; uploading only the moc and textures; uploading a .zip File directly (a zip is not unpacked by this API); settings file named .model3.JSON (uppercase) since endsWith is case-sensitive.","commonSituations":"Users dropping the texture folder instead of the model root; directory uploads where webkitRelativePath is empty because files were picked file-by-file; case-sensitivity on Windows-created archives; distributing models without their settings export.","solutions":["Upload an archive/folder that contains the .model3.json (Cubism 4) or .model.json (Cubism 2) next to its assets","If you must accept bare moc+textures, detect that case first and build fake settings via createFakeSettings instead of FileLoader.createSettings","Filter client-side: warn when no selected file matches /\\.model3?\\.json$/i before invoking the loader","Ensure directory upload is used (webkitdirectory) so webkitRelativePath is populated and nested settings are found"],"exampleFix":"// before\nconst settings = await FileLoader.createSettings(selectedFiles) // TypeError('Settings file not found')\n\n// after\nconst settingsFile = selectedFiles.find(f => /\\.model3?\\.json$/i.test(f.webkitRelativePath || f.name))\nif (!settingsFile) {\n  throw new Error('Select the model folder including its .model3.json (or .model.json) settings file.')\n}\nconst settings = await FileLoader.createSettings(selectedFiles)","handlingStrategy":"validation","validationCode":"const hasSettings = files.some(f => /\\.model3?\\.json$/i.test(f.webkitRelativePath || f.name))\nif (!hasSettings) throw new Error('Select the model folder containing its .model3.json / .model.json')\nconst settings = await FileLoader.createSettings(files)","typeGuard":"const isSettingsUpload = (files: File[]): boolean => files.some(f => /\\.model3?\\.json$/i.test(f.webkitRelativePath || f.name))","tryCatchPattern":"catch (e) { if (e instanceof TypeError && e.message === 'Settings file not found') { showUploadHint(); return } throw e }","preventionTips":["Use directory upload (webkitdirectory) so webkitRelativePath is populated","Filter/validate the selection client-side before invoking the loader","Educate users to drop the whole model folder, not the textures subfolder"],"tags":["live2d","file-upload","settings-file","webkitdirectory"],"backgroundTag":"live2d-model-load-failed","analyzedSha":"9c213115f8bd0fff9e6eabab02b077ac32da21be","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}