{"record":{"id":"b61c3cd09293ea1a","repo":"moeru-ai/airi","slug":"failed-to-fetch-mmd-model-response-status-re","errorCode":null,"errorMessage":"Failed to fetch MMD model: ${response.status} ${response.statusText}","messagePattern":"Failed to fetch MMD model: (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui-mmd/src/utils/mmd-loader.ts","lineNumber":96,"sourceCode":" *\n * Accepts either a packaged ZIP (the usual distribution form: model plus\n * textures) or a bare `.pmx`/`.pmd` URL. ZIP archives are unpacked to blob\n * URLs and a basename-based texture resolver is installed on the loader; raw\n * URLs are loaded directly and rely on the server's relative paths.\n *\n * The returned `dispose()` revokes any blob URLs created during the load. It\n * does not dispose the mesh's GPU resources — the scene owns that lifecycle.\n */\nexport async function loadMMDModelFromSource(src: string, options: LoadMMDOptions = {}): Promise<ResolvedMMDModel> {\n  const cachedSource = options.cacheKey ? await OPFSCache.get(options.cacheKey, src) : null\n  let buffer: ArrayBuffer\n  if (cachedSource) {\n    buffer = await cachedSource.arrayBuffer()\n  }\n  else {\n    const response = await fetch(src)\n    if (!response.ok)\n      throw new Error(`Failed to fetch MMD model: ${response.status} ${response.statusText}`)\n    buffer = await response.arrayBuffer()\n  }\n\n  if (isZip(buffer)) {\n    const assets = await loadMMDZip(buffer)\n    let mmd: MMD | undefined\n    try {\n      const { loader, manager } = createMMDLoaderContext(assets.urlModifier)\n      mmd = await loadMMD(loader, assets.modelBlobUrl)\n      prepareMMDMaterials(mmd.mesh)\n      if (options.waitForTextures)\n        await waitForManagerIdle(manager)\n      if (options.cacheKey && !cachedSource)\n        await OPFSCache.save(options.cacheKey, new Blob([buffer]), src)\n      return {\n        mmd,\n        mesh: mmd.mesh,\n        format: assets.variant.format,","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-ui-mmd/src/utils/mmd-loader.ts#L78-L114","documentation":"`loadMMDModelFromSource(src, options)` fetches the MMD model bytes via `fetch(src)`. If the response is not OK (`!response.ok`, i.e. HTTP status outside 200–299) it throws `Failed to fetch MMD model: <status> <statusText>`. The OPFSCache path is only taken when a cache hit exists, so a network/origin error surfaces here.","triggerScenarios":"A `src` URL that returns 404 (model not found), 403 (auth/CORS), 500 (server error), a wrong base URL, a CDN path typo, or a cross-origin resource without proper CORS headers returning an opaque/error response. Also a server temporarily down returning 502/503.","commonSituations":"Wrong asset URL after a deploy/rename; missing CORS configuration on the model host; expired signed URL; the model file was never uploaded; reverse proxy returning HTML error pages with HTTP 200 (those slip through but fail later) vs a real non-2xx.","solutions":["Verify the `src` URL resolves in a browser/curl and returns the expected `.pmx`/`.pmd`/`.zip` bytes with HTTP 200.","Add CORS headers (`Access-Control-Allow-Origin`) on the hosting origin for the model path.","Provide a working `options.cacheKey` so a previously cached copy is used when the network fails.","Catch the error and offer a retry or a fallback model URL."],"exampleFix":"// before\nconst mmd = await loadMMDModelFromSource(src)\n\n// after\nconst res = await fetch(src, { method: 'HEAD' }).catch(() => null)\nif (!res || !res.ok) throw new Error(`MMD source unreachable at ${src} (HTTP ${res?.status ?? 'no response'})`)\nconst mmd = await loadMMDModelFromSource(src, { cacheKey: `mmd:${src}` })","handlingStrategy":"retry","validationCode":"async function isMMDSrcReachable(src: string): Promise<boolean> {\n  try {\n    const r = await fetch(src, { method: 'HEAD' })\n    return r.ok\n  } catch { return false }\n}\n\nif (await isMMDSrcReachable(src)) await loadMMDModelFromSource(src, { cacheKey: `mmd:${src}` })","typeGuard":null,"tryCatchPattern":"let lastErr: unknown\nfor (const url of [src, fallbackSrc]) {\n  try {\n    return await loadMMDModelFromSource(url, { cacheKey: `mmd:${url}` })\n  } catch (e) {\n    lastErr = e\n    if (!(e instanceof Error && e.message.startsWith('Failed to fetch MMD model'))) throw e\n  }\n}\nthrow lastErr","preventionTips":["Verify the model URL returns HTTP 200 before loading.","Configure CORS on the model host.","Pass options.cacheKey so OPFSCache can serve on transient failures.","Provide a fallback URL for resilience."],"tags":["mmd","model-loading","network","fetch","cors"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}