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

  1. 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
  2. If content is fine, check that only pixi-live2d-display cubism4/cubism2 runtimes you expect are registered — findRuntime iterates registered runtimes
  3. Re-export the model from the official editor instead of hand-crafting JSON
  4. 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

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


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)