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
- Open the archive and verify the .model3.json actually has content (e.g. unzip -l for size, then cat the file)
- Re-export the model from the Cubism editor or re-download the archive if the entry is 0 bytes
- Wrap loads in try/catch and show the `url` from the message so users know which file in their ZIP is blank
- 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
- Check entry sizes when unzipping (0-byte model3.json is the signature)
- Re-export from the Cubism editor rather than hand-editing archives
- Report the offending url from the message so users can self-serve
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
- Archive entry not found
- Cannot find file
- Expected a JSON object in
- Expected exactly one moc file, got
- No Live2D model source provided.
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)