moeru-ai/airi · error · Error

Empty settings file

Error message

Empty settings file: ${url}

What it means

Thrown by createModelSettings in the Live2D ZIP loader when the text read for a settings file (.model3.json / .model.json) is an empty string. The loader found a settings entry by name but its content is blank, so JSON.parse would fail later anyway; this check fails fast with the offending `url` in the message.

Solutions

  1. Open the archive and verify the .model3.json actually has content (e.g. unzip -l for size, then cat the file)
  2. Re-export the model from the Cubism editor or re-download the archive if the entry is 0 bytes
  3. Wrap loads in try/catch and show the `url` from the message so users know which file in their ZIP is blank
  4. If you generate archives programmatically, assert entry text is non-empty before adding it

Example fix

// before
const settings = createModelSettings(text, url) // text === ''

// after
if (!text.trim()) {
  throw new Error(`Settings file "${url}" is empty — the archive is truncated or the export failed. Re-export and re-zip the model.`)
}
const settings = createModelSettings(text, url)
Defensive patterns

Strategy: validation

Validate before calling

const text = await zipEntry.async('text')
if (!text.trim()) {
  throw new Error(`Settings entry "${path}" is empty — re-export or re-download the archive`)
}
const settings = createModelSettings(text, path)

Try / catch

catch (e) { if (e.message.startsWith('Empty settings file')) { showUserError(`The model's settings file (${e.message.split(': ')[1]}) is blank; the ZIP is corrupt`); return } throw e }

Prevention

When it happens

Trigger: Loading a ZIP whose .model3.json entry is 0 bytes; a settings entry that contains only whitespace after sanitizeModelSettingsText; selecting an empty/truncated file in the FileLoader.createSettings upload path which reads text then calls createModelSettings.

Common situations: Broken export from Live2D Cubism editor (empty model3.json), ZIP truncated during download or by git-lfs pointer mishandling, archives packaged by tools that write placeholder files, or an interrupted save leaving a blank file.

Related errors


AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-08-18). Data as JSON: /api/errors/2e9758c851ef2f53. Report an issue: GitHub.

Appendix: source

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

function normalizeLive2DArchivePath(path: string): string {
  try {
    return decodeURI(path)
  }
  catch {
    // Malformed percent escapes cannot be URI-decoded and therefore represent a literal archive path.
    return path
  }
}

function useArchivePathResolution(settings: ModelSettings): ModelSettings {
  const resolveURL = settings.resolveURL.bind(settings)
  settings.resolveURL = path => normalizeLive2DArchivePath(resolveURL(path))
  return settings
}

function createModelSettings(text: string, url: string): ModelSettings {
  if (!text) {
    throw new Error(`Empty settings file: ${url}`)
  }

  const settingsJSON = JSON.parse(text) as JSONObject & { url?: string }
  settingsJSON.url = url
  const runtime = Live2DFactory.findRuntime(settingsJSON)

  if (!runtime) {
    throw new Error('Unknown settings JSON')
  }

  return useArchivePathResolution(runtime.createModelSettings(settingsJSON))
}

export function isSettingsFile(file: string) {
  return !shouldIgnoreLive2DArchiveEntry(file)
    && !file.endsWith('items_pinned_to_model.json')
    && (file.endsWith('.model3.json') || file.endsWith('.model.json'))
}

View on GitHub (pinned to 9c213115f8)