moeru-ai/airi · error · Error
Expected exactly one moc file, got ${mocFiles.length} ${file
Error message
Expected exactly one moc file, got ${mocFiles.length} ${fileList} What it means
`createFakeSettings(files)` builds a synthetic `Cubism4ModelSettings` when no `.model3.json` is present. It filters `files` for moc files (`isMocFile`) and requires exactly one; otherwise it throws `Expected exactly one moc file, got <count> <fileList>`. With one moc it synthesizes a manifest; with zero or more than one it aborts.
Source
Thrown at packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts:166
}
export function isMocFile(file: string) {
return file.endsWith('.moc3')
}
export function basename(path: string): string {
// https://stackoverflow.com/a/15270931
return path.split(/[\\/]/).pop()!
}
// copy and modified from https://github.com/guansss/live2d-viewer-web/blob/f6060b2ce52c2e26b6b61fa903c837fe343f72d1/src/app/upload.ts#L81-L142
function createFakeSettings(files: string[]): ModelSettings {
const mocFiles = files.filter(file => isMocFile(file))
if (mocFiles.length !== 1) {
const fileList = mocFiles.length ? `(${mocFiles.map(f => `"${f}"`).join(',')})` : ''
throw new Error(`Expected exactly one moc file, got ${mocFiles.length} ${fileList}`)
}
const mocFile = mocFiles[0]
const modelName = basename(mocFile).replace(/\.moc3?/, '')
const textures = files.filter(f => f.endsWith('.png'))
if (!textures.length) {
throw new Error('Textures not found')
}
const motions = files.filter(f => f.endsWith('.mtn') || f.endsWith('.motion3.json'))
const physics = files.find(f => f.includes('physics'))
const pose = files.find(f => f.includes('pose'))
const settings = new Cubism4ModelSettings({
url: `${modelName}.model3.json`,
Version: 3,View on GitHub (pinned to 27111382b4)
Solutions
- Ensure the archive contains exactly one `.moc3` (or `.moc`) file at the expected location.
- If the archive holds multiple models, split it into one archive per model, or supply a real `.model3.json` so `createFakeSettings` is not used.
- Inspect the echoed `<fileList>` to identify and remove the extra moc.
- If a `.model3.json` exists, let the normal settings path run instead of falling back to fake settings.
Example fix
// before
// user archive with two moc3 files -> throws in createFakeSettings
// after
// package one model per archive, or include a model3.json so the manifest path is used
const mocs = files.filter(isMocFile)
if (mocs.length !== 1) {
throw new Error(`Archive must contain exactly one moc file; found ${mocs.length}: ${mocs.join(', ')}`)
} Defensive patterns
Strategy: validation
Validate before calling
const mocs = files.filter(isMocFile)
if (mocs.length !== 1)
throw new Error(`Expected exactly one moc file, got ${mocs.length}`)
createFakeSettings(files) Type guard
function hasExactlyOneMoc(files: string[]): boolean {
return files.filter(isMocFile).length === 1
} Try / catch
try {
await loadLive2DFromArchive(blob)
} catch (e) {
if (e instanceof Error && e.message.includes('one moc file')) {
// ask user to pick an archive with a single model
} else throw e
} Prevention
- Package one model per archive or include a real model3.json.
- Validate moc count before loading.
- Inspect the echoed fileList to find duplicates.
When it happens
Trigger: An archive with zero `.moc3`/`.moc` files (moc missing), or an archive containing two or more moc files (multiple models bundled together). `fileList` is empty when count is 0, or a parenthesized list of paths when count > 1.
Common situations: User dropped a ZIP that contains multiple characters/moc files in one folder; the moc file was renamed or omitted during packaging; a texture-only archive; a Cubism 2 archive loaded through the Cubism 4 fake-settings path.
Related errors
- Empty settings file: ${url}
- 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/b7539c3470cfe575.
Report an issue: GitHub.