{"record":{"id":"6677f695f2a20da5","repo":"moeru-ai/airi","slug":"textures-not-found","errorCode":null,"errorMessage":"Textures not found","messagePattern":"Textures not found","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts","lineNumber":175,"sourceCode":"}\n\n// copy and modified from https://github.com/guansss/live2d-viewer-web/blob/f6060b2ce52c2e26b6b61fa903c837fe343f72d1/src/app/upload.ts#L81-L142\nfunction createFakeSettings(files: string[]): ModelSettings {\n  const mocFiles = files.filter(file => isMocFile(file))\n\n  if (mocFiles.length !== 1) {\n    const fileList = mocFiles.length ? `(${mocFiles.map(f => `\"${f}\"`).join(',')})` : ''\n\n    throw new Error(`Expected exactly one moc file, got ${mocFiles.length} ${fileList}`)\n  }\n\n  const mocFile = mocFiles[0]\n  const modelName = basename(mocFile).replace(/\\.moc3?/, '')\n\n  const textures = files.filter(f => f.endsWith('.png'))\n\n  if (!textures.length) {\n    throw new Error('Textures not found')\n  }\n\n  const motions = files.filter(f => f.endsWith('.mtn') || f.endsWith('.motion3.json'))\n  const physics = files.find(f => f.includes('physics'))\n  const pose = files.find(f => f.includes('pose'))\n\n  const settings = new Cubism4ModelSettings({\n    url: `${modelName}.model3.json`,\n    Version: 3,\n    FileReferences: {\n      Moc: mocFile,\n      Textures: textures,\n      Physics: physics,\n      Pose: pose,\n      Motions: motions.length\n        ? {\n            '': motions.map(motion => ({ File: motion })),\n          }","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts#L157-L193","documentation":"Inside `createFakeSettings`, after locating the single moc file, the loader filters `files` for `.png` entries as textures. If none are found it throws `Textures not found`. A Cubism model requires at least one texture page; the synthetic manifest cannot be built without one.","triggerScenarios":"An archive that has a moc but no `.png` textures — textures were omitted, stored in an unsupported format (e.g. `.webp`/`.jpg` only), placed in a nested folder the flat filter still sees but with wrong casing, or stripped during packaging.","commonSituations":"Texture files renamed to non-png formats; an archive where textures live in a folder that was excluded; case-sensitivity on a case-sensitive filesystem (`.PNG` vs `.png` is matched, but typos like `.pn` fail); a model exported with textures referenced but not bundled.","solutions":["Confirm the archive contains `.png` texture files alongside the moc.","Re-export from the Live2D Cubism tool ensuring textures are bundled.","If only `.webp`/`.jpg` exist, convert them to `.png` or supply a real `model3.json` that lists the alternate texture URIs.","Check for case mismatches and ZIP path issues (folders, backslashes)."],"exampleFix":"// before\n// archive has moc but textures are .webp only -> throws\n\n// after\n// ensure at least one .png ships in the archive\nconst textures = files.filter(f => f.toLowerCase().endsWith('.png'))\nif (!textures.length) throw new Error('Archive must include at least one .png texture')","handlingStrategy":"validation","validationCode":"const textures = files.filter(f => f.toLowerCase().endsWith('.png'))\nif (!textures.length)\n  throw new Error('Archive must include at least one .png texture')\ncreateFakeSettings(files)","typeGuard":"function hasPngTextures(files: string[]): boolean {\n  return files.some(f => f.toLowerCase().endsWith('.png'))\n}","tryCatchPattern":"try {\n  await loadLive2DFromArchive(blob)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Textures not found') {\n    // ask user to include .png textures\n  } else throw e\n}","preventionTips":["Ensure the archive bundles .png textures.","Re-export with textures included.","Watch for case mismatches on texture extensions."],"tags":["live2d","model-loading","archive","textures"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}