moeru-ai/airi · error · Error
Archive entry not found: ${filePath}
Error message
Archive entry not found: ${filePath} What it means
readJsonObject looks up an entry inside a parsed JSZip archive by exact path and parses it as a JSON object. It throws this Error when zip.file(filePath) returns undefined, meaning no entry with that exact path exists in the ZIP. validateLive2DZip calls it for the model's settings/display JSON files discovered earlier in the archive listing.
Source
Thrown at packages/stage-ui-live2d/src/utils/live2d-validator.ts:183
if (!Array.isArray(definitions))
continue
for (const definition of definitions) {
if (!isRecord(definition))
continue
const file = readString(definition.File)
if (file)
references.push(file)
}
}
return references
}
async function readJsonObject(zip: JSZip, filePath: string): Promise<Record<string, unknown>> {
const file = zip.file(filePath)
if (!file)
throw new Error(`Archive entry not found: ${filePath}`)
const value: unknown = JSON.parse(await file.async('text'))
if (!isRecord(value))
throw new TypeError(`Expected a JSON object in ${filePath}`)
return value
}
function addIssue(
report: Live2DValidationReport,
code: Live2DValidationIssueCode,
severity: Live2DValidationIssueSeverity,
message: string,
resolution: string,
): void {
report.issues.push({ code, severity, message, resolution })
}
function checkReference(View on GitHub (pinned to 9c213115f8)
Solutions
- Open the ZIP and verify the exact entry name; align the requested filePath with the entry (case, extension, separators)
- Normalize paths (strip leading './', '/', decode percent-encoding, convert backslashes to '/') before zip.file lookup
- Re-export the ZIP so entry names match what the settings JSON references
- Check that the referenced file was not stripped when the archive was built (some tools exclude unused files)
Example fix
// before
const file = zip.file('./model/model3.json') // entry is 'model/model3.json'
// after
const normalized = filePath.replace(/^\.?\//, '').replace(/\\/g, '/')
const file = zip.file(normalized) Defensive patterns
Strategy: try-catch
Validate before calling
function hasArchiveEntry(zip: JSZip, filePath: string): boolean {
const normalized = filePath.replace(/^\.?\//, '').replace(/\\/g, '/')
return !!zip.file(normalized)
}
// check every referenced JSON path with hasArchiveEntry before validating Type guard
function zipHasFile(zip: JSZip, path: string): boolean {
return typeof zip.file(path)?.async === 'function'
} Try / catch
try {
const info = await readJsonObject(zip, filePath)
} catch (e) {
if (e instanceof Error && e.message.startsWith('Archive entry not found:')) {
const missing = e.message.slice('Archive entry not found: '.length)
// list zip.files, suggest nearest match (case/separator diff)
} else throw e
} Prevention
- Normalize entry paths (case, separators, leading './') before zip.file lookups
- List zip.files and cross-check settings-referenced paths before validation
- Build archives with a tool that preserves the exact filenames the settings JSON references
- Do not rename entries inside exported Live2D model ZIPs
When it happens
Trigger: Calling validateLive2DZip (or countParsedJsonResources/displayInfo) with a ZIP whose referenced JSON path does not match any archive entry exactly — e.g. path case mismatch, leading './' or '/' prefixes, URL-encoded characters, or a settings file listing a nested model3.json path that is absent.
Common situations: Live2D settings files referencing textures/motions with paths differing in case or separators from actual entries; ZIPs created on different OSes normalizing names differently; renamed files inside the archive without updating the settings JSON.
Related errors
- Empty settings file: ${url}
- Expected exactly one moc file, got ${mocFiles.length} ${file
- Textures not found
- Cannot find file: ${path}
- [ZipLoader] Failed to extract CDI/EXP metadata:
AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-09-02).
Data as JSON: /api/errors/bce5595dd726aada.
Report an issue: GitHub.