moeru-ai/airi · error · Error
Unknown settings JSON
Error message
Unknown settings JSON
What it means
Thrown by createModelSettings when Live2DFactory.findRuntime(settingsJSON) returns undefined, i.e. pixi-live2d-display could not recognize the parsed JSON as either a Cubism 2 (.model.json) or Cubism 4 (.model3.json) settings document. Recognition is content-based (runtime-sniffing fields like FileReferences/Version/Moc), so a syntactically valid JSON that lacks those markers — a motion3.json, physics, or a hand-written file — is 'unknown'.
Solutions
- Verify the file is a genuine model settings export: it should contain FileReferences (with Moc and Textures) for Cubism 4, or the classic model.json fields for Cubism 2
- If content is fine, check that only pixi-live2d-display cubism4/cubism2 runtimes you expect are registered — findRuntime iterates registered runtimes
- Re-export the model from the official editor instead of hand-crafting JSON
- Catch the error and report the settings URL so the user can inspect that specific file
Example fix
// before
const settings = createModelSettings(text, url) // 'Unknown settings JSON'
// after
const json = JSON.parse(text)
const looksCubism4 = typeof json.Version === 'number' && json.FileReferences?.Moc
if (!looksCubism4 && json.model?.textures == null) {
throw new Error(`"${url}" does not look like a Cubism 2/4 model settings file (missing FileReferences.Moc or model.textures)`)
}
const settings = createModelSettings(text, url) Defensive patterns
Strategy: try-catch
Validate before calling
const json = JSON.parse(text)
const isCubism4 = typeof json?.Version !== 'undefined' && !!json?.FileReferences?.Moc
const isCubism2 = Array.isArray(json?.model?.textures)
if (!isCubism4 && !isCubism2) throw new Error(`${url} is not a recognized Cubism 2/4 settings document`) Type guard
function looksLikeModelSettings(json: any): boolean {
return Boolean(json && (json.FileReferences?.Moc || Array.isArray(json.model?.textures)))
} Try / catch
catch (e) { if (e.message === 'Unknown settings JSON') { showUserError('This settings file is not a Cubism 2/4 model export. Re-export from the official editor.'); return } throw e } Prevention
- Only feed genuine editor-exported model3.json/model.json files to the loader
- Don't rename motion/physics JSONs to .model3.json
- Keep runtime detection libs (pixi-live2d-display cubism2/4) registered
When it happens
Trigger: Passing a .model3.json whose top-level keys were renamed or stripped; a settings file that is actually a pose/physics/motion JSON misnamed as model3.json; a JSON whose 'Version'/'FileReferences' structure doesn't match what the Cubism4 runtime detector expects; corrupt JSON that parsed to something other than a settings object.
Common situations: Renaming exp3.json or other files to .model3.json to satisfy isSettingsFile; editing settings JSON and accidentally changing the case of keys; mixing Cubism2-only fields so neither runtime claims it; tooling that re-serializes JSON and drops fields with falsy values (e.g. deletes Version: 3 treated as removable).
Related errors
- A motion sample occurs after the recording duration.
- Archive entry not found
- Cannot find file
- Cannot set motion: model not loaded
- Empty settings file
AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-08-18).
Data as JSON: /api/errors/e2173ccb69d670c9.
Report an issue: GitHub.
Appendix: source
Thrown at packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts:139
}
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'))
}
export function isMocFile(file: string) {
return file.endsWith('.moc3')
}
export function basename(path: string): string {
// https://stackoverflow.com/a/15270931
return path.split(/[\\/]/).pop()!View on GitHub (pinned to 9c213115f8)