{"record":{"id":"bce5595dd726aada","repo":"moeru-ai/airi","slug":"archive-entry-not-found-filepath","errorCode":null,"errorMessage":"Archive entry not found: ${filePath}","messagePattern":"Archive entry not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui-live2d/src/utils/live2d-validator.ts","lineNumber":183,"sourceCode":"    if (!Array.isArray(definitions))\n      continue\n\n    for (const definition of definitions) {\n      if (!isRecord(definition))\n        continue\n\n      const file = readString(definition.File)\n      if (file)\n        references.push(file)\n    }\n  }\n  return references\n}\n\nasync function readJsonObject(zip: JSZip, filePath: string): Promise<Record<string, unknown>> {\n  const file = zip.file(filePath)\n  if (!file)\n    throw new Error(`Archive entry not found: ${filePath}`)\n\n  const value: unknown = JSON.parse(await file.async('text'))\n  if (!isRecord(value))\n    throw new TypeError(`Expected a JSON object in ${filePath}`)\n  return value\n}\n\nfunction addIssue(\n  report: Live2DValidationReport,\n  code: Live2DValidationIssueCode,\n  severity: Live2DValidationIssueSeverity,\n  message: string,\n  resolution: string,\n): void {\n  report.issues.push({ code, severity, message, resolution })\n}\n\nfunction checkReference(","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/moeru-ai/airi/blob/9c213115f8bd0fff9e6eabab02b077ac32da21be/packages/stage-ui-live2d/src/utils/live2d-validator.ts#L165-L201","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nconst file = zip.file('./model/model3.json') // entry is 'model/model3.json'\n// after\nconst normalized = filePath.replace(/^\\.?\\//, '').replace(/\\\\/g, '/')\nconst file = zip.file(normalized)","handlingStrategy":"try-catch","validationCode":"function hasArchiveEntry(zip: JSZip, filePath: string): boolean {\n  const normalized = filePath.replace(/^\\.?\\//, '').replace(/\\\\/g, '/')\n  return !!zip.file(normalized)\n}\n// check every referenced JSON path with hasArchiveEntry before validating","typeGuard":"function zipHasFile(zip: JSZip, path: string): boolean {\n  return typeof zip.file(path)?.async === 'function'\n}","tryCatchPattern":"try {\n  const info = await readJsonObject(zip, filePath)\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Archive entry not found:')) {\n    const missing = e.message.slice('Archive entry not found: '.length)\n    // list zip.files, suggest nearest match (case/separator diff)\n  } else throw e\n}","preventionTips":["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"],"tags":["live2d","zip","validation"],"backgroundTag":"archive-entry-not-found","analyzedSha":"9c213115f8bd0fff9e6eabab02b077ac32da21be","analyzedAt":"2026-09-02T04:27:24.639Z","contentChangedAt":"2026-09-02T04:27:24.639Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}