{"record":{"id":"808c4271a1369cbd","repo":"mastra-ai/mastra","slug":"artifact-upload-failed-uploadresp-status-upl","errorCode":null,"errorMessage":"Artifact upload failed: ${uploadResp.status} ${uploadResp.statusText}","messagePattern":"Artifact upload failed: (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/server/platform-api.ts","lineNumber":175,"sourceCode":"      postCancel: c2 => c2.POST('/v1/server/deploys/{id}/cancel', { params: { path: { id } } }),\n      client: c,\n      deployId: id,\n    });\n\n  // Step 2: Upload artifact to the signed URL\n  try {\n    if (uploadUrl.startsWith('file://')) {\n      const { writeFile } = await import('node:fs/promises');\n      const { fileURLToPath } = await import('node:url');\n      await writeFile(fileURLToPath(uploadUrl), Buffer.from(zipBuffer));\n    } else {\n      const uploadResp = await fetch(uploadUrl, {\n        method: 'PUT',\n        headers: { 'Content-Type': 'application/zip' },\n        body: new Uint8Array(zipBuffer),\n      });\n      if (!uploadResp.ok) {\n        throw new Error(`Artifact upload failed: ${uploadResp.status} ${uploadResp.statusText}`);\n      }\n    }\n  } catch (uploadError) {\n    await cancel(client);\n    throw uploadError;\n  }\n\n  // Step 3: Notify API that upload is complete → triggers build pipeline\n  await confirmUploadWithRetry({\n    postUploadComplete: c => c.POST('/v1/server/deploys/{id}/upload-complete', { params: { path: { id } } }),\n    cancelDeploy: cancel,\n    client,\n    orgId,\n  });\n\n  return { id, status };\n}\n","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/cli/src/commands/server/platform-api.ts#L157-L193","documentation":"The CLI PUTs the zipped artifact to the signed uploadUrl (S3-style) and requires a 2xx. Any non-ok response is wrapped as 'Artifact upload failed: <status> <statusText>'. On this failure the deploy is best-effort cancelled so no orphaned pending deploy remains.","triggerScenarios":"Signed URL expired between deploy creation and upload (slow packaging, long gap); wrong Content-Type rejected by storage; network interruption or proxy blocking large PUT bodies; zip exceeds storage size limit (413); storage credentials/permission issues server-side (403).","commonSituations":"Uploading very large bundles over flaky corporate networks/VPN; CI runners with small egress limits hitting 413; long builds letting the pre-signed URL lapse (403); intercepting proxies returning 403/407.","solutions":["Retry the deploy (a fresh signed URL is issued each run)","Reduce artifact size (prune node_modules/unused assets before packaging, check the zip contents)","Check proxy/firewall allows large PUT uploads to the storage host","If 403/expire errors persist, investigate clock skew on the machine and platform-side storage permissions"],"exampleFix":"// before: uploading a bloated bundle\nzip -r bundle.zip .   # includes node_modules, .git\n// after: package only the build output\nmastra build && mastra server deploy  # CLI packages .mastra/output only","handlingStrategy":"retry","validationCode":"// Pre-check artifact size before upload (avoid 413)\nimport { stat } from 'node:fs/promises';\nconst { size } = await stat(zipPath);\nconst MAX = 500 * 1024 * 1024;\nif (size > MAX) throw new Error(`Artifact ${size} bytes exceeds ${MAX} — slim the bundle before deploying.`);","typeGuard":null,"tryCatchPattern":"try {\n  await deploy();\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Artifact upload failed:')) {\n    if (/\\b(502|503|504)\\b/.test(err.message)) {\n      await sleep(5000);\n      return deploy(); // transient gateway error — safe to retry, new URL issued\n    }\n    console.error('Upload rejected; check artifact size, URL expiry, and proxy rules:', err.message);\n  }\n  throw err;\n}","preventionTips":["Deploy promptly after build so the signed URL doesn't expire","Keep artifacts small; inspect the zip for accidental node_modules/.git inclusion","Ensure proxies/firewalls permit large PUT uploads to the storage host","Keep machine clocks synced (pre-signed URL validation)"],"tags":["network","upload","http","storage"],"backgroundTag":"artifact-upload-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}