moeru-ai/airi · error · Error
Empty settings file: ${url}
Error message
Empty settings file: ${url} What it means
`createModelSettings(text, url)` builds a Live2D `ModelSettings` from the raw text of a `.model3.json` / `.model.json` file. It throws `Empty settings file: <url>` when `text` is falsy (empty string) before `JSON.parse` is attempted. The `<url>` identifies which settings file was empty.
Source
Thrown at packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts:130
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 27111382b4)
Solutions
- Re-download or re-export the model from its source tool.
- Verify the archive before loading: check that the settings entry has non-zero size (`zip.file(path)?._data?.uncompressedSize`).
- Validate the ZIP integrity (e.g. `unzip -t`) and confirm the settings file is not empty.
- Catch the error and prompt the user to pick a different/complete archive.
Example fix
// before
const settings = await ZipLoader.loadAsync(blob).then(z => createModelSettingsFromZip(z))
// after
const zip = await JSZip.loadAsync(blob)
const entry = zip.file(settingsPath)
if (!entry) throw new Error(`Missing ${settingsPath} in archive`)
const text = await entry.async('text')
if (!text.trim()) throw new Error(`${settingsPath} is empty; archive may be corrupt`)
const settings = createModelSettings(text, settingsPath) Defensive patterns
Strategy: validation
Validate before calling
const text = await zipEntry.async('text')
if (!text || !text.trim())
throw new Error(`${path} is empty; re-export or re-download the model`)
const settings = createModelSettings(text, path) Type guard
function isNonEmptySettingsText(text: unknown): text is string {
return typeof text === 'string' && text.trim().length > 0
} Try / catch
try {
await loadLive2DFromArchive(blob)
} catch (e) {
if (e instanceof Error && e.message.startsWith('Empty settings file')) {
// tell user the manifest is empty; offer re-download
} else throw e
} Prevention
- Validate archive entry sizes are non-zero before reading.
- Re-download interrupted model archives.
- Check ZIP integrity before loading.
When it happens
Trigger: The settings JSON file inside a Live2D ZIP/archive resolved to zero bytes: a truncated download, a corrupt archive entry, a zero-length `model3.json`, or `ZipLoader.readText` returning `''` for a settings entry.
Common situations: An interrupted download where the `.model3.json` is partially written; a ZIP that compressed a 0-byte placeholder file; an archive produced by a tool that wrote the moc/textures but left the manifest empty; a CDN/proxy returning an empty body with HTTP 200.
Related errors
- Expected exactly one moc file, got ${mocFiles.length} ${file
- Textures not found
- Cannot find file: ${path}
- Settings file not found
- MMD ZIP must contain a .pmx or .pmd model file
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/2e9758c851ef2f53.
Report an issue: GitHub.