moeru-ai/airi · error · TypeError

Settings file not found

Error message

Settings file not found

What it means

`FileLoader.createSettings(files)` searches the uploaded file list for a settings file (`isSettingsFile` — a `.model3.json`/`.model.json`, excluding ignored entries). If none is found it throws `Settings file not found` (as a `TypeError`). This is the entry-point used when the user selects files/folders through an `<input>` rather than a ZIP.

Source

Thrown at packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts:223

ZipLoader.readText = async (jsZip: JSZip, path: string) => {
  const file = jsZip.file(path)

  if (!file) {
    throw new Error(`Cannot find file: ${path}`)
  }

  const text = await file.async('text')

  return isSettingsFile(path) ? sanitizeModelSettingsText(text) : text
}

const defaultFileLoaderReadText = FileLoader.readText
FileLoader.createSettings = async (files: File[]) => {
  const settingsFile = files.find(file => isSettingsFile(file.webkitRelativePath || file.name))

  if (!settingsFile) {
    throw new TypeError('Settings file not found')
  }

  const settingsUrl = settingsFile.webkitRelativePath || settingsFile.name
  const settingsText = await FileLoader.readText(settingsFile)
  const settings = createModelSettings(settingsText, settingsUrl)
  Object.assign(settings, { _objectURL: URL.createObjectURL(settingsFile) })

  return settings
}

FileLoader.readText = async (file: File) => {
  const text = await defaultFileLoaderReadText(file)
  const path = file.webkitRelativePath || file.name

  return isSettingsFile(path) ? sanitizeModelSettingsText(text) : text
}

ZipLoader.getFilePaths = (jsZip: JSZip) => {

View on GitHub (pinned to 27111382b4)

Solutions

  1. Instruct the user to select the folder that contains the `.model3.json` (the whole model folder, not just textures).
  2. Pre-validate the file list before calling `FileLoader.createSettings`: `files.some(f => isSettingsFile(f.webkitRelativePath || f.name))`.
  3. Confirm the settings file is not being caught by `shouldIgnoreLive2DArchiveEntry`.
  4. Fall back to ZIP upload if folder selection omits the manifest.

Example fix

// before
const settings = await FileLoader.createSettings(selectedFiles)  // throws

// after
const hasSettings = selectedFiles.some(f => isSettingsFile(f.webkitRelativePath || f.name))
if (!hasSettings)
  throw new Error('Select the model folder containing the .model3.json file')
const settings = await FileLoader.createSettings(selectedFiles)
Defensive patterns

Strategy: validation

Validate before calling

const ok = files.some(f => isSettingsFile(f.webkitRelativePath || f.name))
if (!ok) throw new Error('Select the model folder containing the .model3.json')
await FileLoader.createSettings(files)

Type guard

function hasLive2DSettingsFile(files: File[]): boolean {
  return files.some(f => isSettingsFile(f.webkitRelativePath || f.name))
}

Try / catch

try {
  await FileLoader.createSettings(files)
} catch (e) {
  if ((e instanceof Error || e instanceof TypeError) && /Settings file not found/.test(e.message)) {
    // prompt user to select the whole model folder
  } else throw e
}

Prevention

When it happens

Trigger: The user selected a folder or set of files that contains no `.model3.json` / `.model.json`; the settings file has an unexpected extension; the settings file is present but matched by `shouldIgnoreLive2DArchiveEntry` or is `items_pinned_to_model.json`.

Common situations: User selected only the moc/textures but not the manifest; user selected a non-Live2D folder; the `.model3.json` was renamed; webkitRelativePath not exposed so the name check failed; the folder contains a settings file that the ignore filter excluded.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/31aa5f442108f52b. Report an issue: GitHub.