{"record":{"id":"50d4b01adc73fada","repo":"moeru-ai/airi","slug":"failed-to-download-mediapipe-vision-task-asset-for","errorCode":null,"errorMessage":"Failed to download MediaPipe vision task asset for ${key} after ${attempt} attempts","messagePattern":"Failed to download MediaPipe vision task asset for (.+?) after (.+?) attempts","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/model-driver-mediapipe/tasks/prepare-tasks.ts","lineNumber":75,"sourceCode":"      await fs.writeFile(tempPath, Buffer.from(response))\n      await fs.rename(tempPath, outputPath)\n      console.log(`MediaPipe vision task asset for ${key} saved to ${outputPath}`)\n    }\n    finally {\n      await fs.rm(tempPath, { force: true })\n    }\n  }, {\n    onError: (error) => {\n      const message = errorMessageFromValue(error)\n      console.warn(`Failed to download MediaPipe vision task asset for ${key} (attempt ${attempt}): ${message}`)\n    },\n  })\n\n  try {\n    await downloadWithRetry()\n  }\n  catch (error) {\n    throw new Error(`Failed to download MediaPipe vision task asset for ${key} after ${attempt} attempts`, {\n      cause: error,\n    })\n  }\n}\n\nawait fs.mkdir(assetsRoot, { recursive: true })\n\nfor (const { key, source, outputPath } of taskTargets) {\n  if (await isUsableFile(outputPath)) {\n    console.log(`MediaPipe vision task asset for ${key} already exists at ${outputPath}, skipping download.`)\n    continue\n  }\n  await downloadAsset(key, source, outputPath)\n\n  if (!await isUsableFile(outputPath))\n    throw new Error(`Failed to ensure MediaPipe vision task asset for ${key}: missing or empty file at ${outputPath}`)\n}\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/model-driver-mediapipe/tasks/prepare-tasks.ts#L57-L93","documentation":"Thrown by downloadAsset() in prepare-tasks.ts after withRetry exhausts all attempts to download a MediaPipe vision task model. The thrown Error wraps the last failure via { cause: error }. The script is a top-level-await build preparation step that fetches pose/hand/face .task model files from storage.googleapis.com.","triggerScenarios":"Running the prepare-tasks script (postinstall or build) with no/slow network; DNS or TLS failure to storage.googleapis.com; a model URL changed or is rate-limited (HTTP 429); corporate proxy blocks the request; disk full so fs.writeFile fails each attempt.","commonSituations":"CI behind a firewall without allow-listing the MediaPipe CDN; flaky home network during install; offline build attempted without pre-cached assets; the upstream Google storage bucket is temporarily unavailable.","solutions":["Retry the build/install once the network is stable; the script resumes and skips already-downloaded files via isUsableFile.","Pre-download the three .task files on a connected machine and commit or vendor them under packages/model-driver-mediapipe/tasks/assets.","Allow-list https://storage.googleapis.com on proxies/CI firewalls.","Inspect error.cause for the underlying fetch error to distinguish network vs. disk vs. HTTP status."],"exampleFix":"# before: fails offline\npnpm -F @proj-airi/model-driver-mediapipe prepare-assets\n# after: pre-place the assets so no download is needed\nmkdir -p packages/model-driver-mediapipe/tasks/assets\ncp /cached/pose_landmarker_lite.task packages/model-driver-mediapipe/tasks/assets/\npnpm -F @proj-airi/model-driver-mediapipe prepare-assets","handlingStrategy":"retry","validationCode":"// Pre-check network reachability and cache presence before running prepare-tasks\nimport { existsSync } from 'node:fs'\n\nconst required = ['pose.task', 'hand.task', 'face.task']\nif (required.every(f => existsSync(`tasks/assets/${f}`))) {\n  // assets cached; prepare-tasks will skip downloads\n} else if (!(await isReachable('storage.googleapis.com'))) {\n  throw new Error('MediaPipe CDN unreachable; cache assets or fix network before building')\n}","typeGuard":null,"tryCatchPattern":"try {\n  await import('./prepare-tasks')\n} catch (error) {\n  if (error instanceof Error && /Failed to download MediaPipe/.test(error.message)) {\n    console.error('Asset download failed. Cause:', error.cause)\n    // instruct user to cache assets or fix network; then re-run\n  }\n  throw error\n}","preventionTips":["Vendor the .task files in CI to avoid runtime downloads.","Allow-list https://storage.googleapis.com on corporate networks.","Inspect error.cause to distinguish network, HTTP status, and disk failures."],"tags":["mediapipe","build","network","assets","retry"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}