mastra-ai/mastra · error · Error

Failed to complete upload: ${(err as { detail?: string }).de

Error message

Failed to complete upload: ${(err as { detail?: string }).detail || completeResp.statusText}

What it means

The final step of uploadToEnvironment signals the platform that the artifact upload finished (upload-complete endpoint). A non-ok response throws with the server's `detail` when available, else statusText. The artifact bytes may already be stored, but the deploy was not finalized, so the platform may keep the deploy in an incomplete state.

Source

Thrown at packages/cli/src/commands/deploy/index.ts:398

    throw new Error(`Failed to upload artifact: ${uploadResp.statusText}`);
  }

  // Signal upload complete — uses net-new env-scoped endpoint so the
  // unified-runtime CLI never touches /v1/studio/*.
  const completeResp = await fetch(
    `${apiUrl}/v1/projects/${projectId}/environments/${environmentId}/deploys/${deploy.id}/upload-complete`,
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${token}`,
        'x-organization-id': orgId,
      },
    },
  );

  if (!completeResp.ok) {
    const err = await completeResp.json().catch(() => ({}));
    throw new Error(`Failed to complete upload: ${(err as { detail?: string }).detail || completeResp.statusText}`);
  }

  return deploy;
}

interface UnifiedDeployStatus {
  id: string;
  status: string;
  instanceUrl: string | null;
  error: string | null;
}

/**
 * Poll the net-new env-scoped status endpoint until the deploy reaches a
 * terminal state. Kept inside the deploy command so the unified runtime
 * never reaches into ../studio/ for transport.
 */
async function streamEnvironmentDeployLogs(

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the `detail` in the message for the server's exact reason
  2. Re-run the deploy end-to-end (a fresh create/upload cycle) rather than retrying only upload-complete
  3. Check token validity/auth duration for long CI jobs and refresh or extend it
  4. Confirm no other deploy pipeline is concurrently targeting the same environment

Example fix

// before
// 40-min CI job, token expires before upload-complete -> 401
// after
// refresh token before deploy step (or use a token with sufficient expiry), re-run deploy
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the token won't expire mid-deploy for long CI jobs
const jobDurationMs = 40 * 60 * 1000;
const tokenTtlMs = getTokenTtl(token); // decode exp from token
if (tokenTtlMs < jobDurationMs) throw new Error('Token expires before deploy can finish; refresh it');

Type guard

function isCompleteUploadFailure(err: unknown): err is Error {
  return err instanceof Error && err.message.startsWith('Failed to complete upload:');
}

Try / catch

try {
  const deploy = await uploadToEnvironment(args);
} catch (err) {
  if (isCompleteUploadFailure(err)) {
    console.error('Deploy not finalized:', err.message);
    // re-run the full deploy (create + upload + complete), not just upload-complete
  } else throw err;
}

Prevention

When it happens

Trigger: The POST to /v1/projects/{projectId}/environments/{environmentId}/deploys/{deploy.id}/upload-complete returns non-2xx — e.g., server-side verification of the uploaded artifact failed, auth expired between steps, or the deploy record was cancelled/unknown.

Common situations: Token expiry mid-deploy in long CI runs; upload-complete racing server-side artifact verification; concurrent deploy superseding this one; platform-side validation rejecting an unexpected artifact layout.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/19860302ede42a1b. Report an issue: GitHub.