{"record":{"id":"544d7c8bd6facac3","repo":"mastra-ai/mastra","slug":"artifact-upload-failed-uploadresp-status-upl-544d7c","errorCode":null,"errorMessage":"Artifact upload failed: ${uploadResp.status} ${uploadResp.statusText}","messagePattern":"Artifact upload failed: (.+?) (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/cli/src/commands/studio/platform-api.ts","lineNumber":190,"sourceCode":"      postCancel: c2 => c2.POST('/v1/studio/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/studio/deploys/{id}/upload-complete', { params: { path: { id } } }),\n    cancelDeploy: cancel,\n    client,\n    orgId,\n  });\n\n  return { id, status };\n}\n","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/cli/src/commands/studio/platform-api.ts#L172-L208","documentation":"After obtaining the presigned uploadUrl, uploadDeploy PUTs the zip artifact to it (expecting Content-Type application/zip). If the storage endpoint responds with a non-2xx status, the command throws with the HTTP status and status text, cancels the deploy record, and rethrows.","triggerScenarios":"The presigned PUT fails: expired/already-used upload URL, oversized zip exceeding storage limits, network interruption mid-upload, storage-side auth rejection, or wrong Content-Type negotiation with the storage backend.","commonSituations":"Large projects producing zips above the upload size limit; slow CI links timing out; retrying a deploy whose uploadUrl was already consumed; corporate proxies blocking large PUT requests to object storage.","solutions":["Retry `mastra studio deploy` — a fresh deploy gets a fresh presigned URL","Reduce artifact size (prune node_modules, exclude dev assets) if the zip may exceed limits","Check network/proxy rules allowing large PUTs to the storage host","Upgrade the CLI in case the storage upload contract changed","If the error persists with 403, report it — presigning may be broken server-side"],"exampleFix":"// before (retry on same URL not possible)\nmastra studio deploy --yes  # Artifact upload failed: 403 Forbidden\n// after (new deploy -> new presigned URL)\nmastra studio deploy --yes  # succeeds","handlingStrategy":"retry","validationCode":"const MAX_ZIP = 100 * 1024 * 1024; // check platform limit\nif (zipBuffer.byteLength > MAX_ZIP) {\n  throw new Error(`Artifact too large: ${zipBuffer.byteLength} bytes`);\n}\nif (!uploadUrl || new URL(uploadUrl).protocol !== 'https:') {\n  throw new Error('Invalid upload URL');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await uploadDeploy(zipBuffer);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Artifact upload failed:')) {\n    console.error('Presigned PUT rejected; get a fresh URL by re-running deploy.');\n    process.exitCode = 3;\n  } else throw e;\n}","preventionTips":["Always obtain a fresh presigned URL per attempt; never reuse upload URLs","Keep deploy zips small (exclude dev dependencies and local assets)","Ensure network/proxy allows large PUTs to the storage host","Use stable, wired connections in CI to avoid mid-upload resets"],"tags":["network","upload","http"],"backgroundTag":"artifact-upload-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}