mastra-ai/mastra · error

No upload URL returned

Error message

No upload URL returned

What it means

uploadServerDeploy creates a deploy via POST /v1/server/deploys, which should return a signed uploadUrl where the zip artifact is PUT. If the API response succeeds (no error field) but uploadUrl is missing/empty, the CLI treats the response as malformed and throws rather than attempting an upload to an undefined URL.

Source

Thrown at packages/cli/src/commands/server/platform-api.ts:152

  const { data, error, response } = await client.POST('/v1/server/deploys', {
    body: {
      projectId,
      projectName: meta?.projectName,
      envVars: meta?.envVars,
      ...(meta?.disablePlatformObservability !== undefined
        ? { disablePlatformObservability: meta.disablePlatformObservability }
        : {}),
    },
  });

  if (error) {
    throwApiError('Deploy failed', response.status, extractApiErrorDetail(error));
  }

  const { id, status, uploadUrl } = data;

  if (!uploadUrl) {
    throw new Error('No upload URL returned');
  }

  const cancel = (c: ReturnType<typeof createApiClient>) =>
    bestEffortCancel({
      postCancel: c2 => c2.POST('/v1/server/deploys/{id}/cancel', { params: { path: { id } } }),
      client: c,
      deployId: id,
    });

  // Step 2: Upload artifact to the signed URL
  try {
    if (uploadUrl.startsWith('file://')) {
      const { writeFile } = await import('node:fs/promises');
      const { fileURLToPath } = await import('node:url');
      await writeFile(fileURLToPath(uploadUrl), Buffer.from(zipBuffer));
    } else {
      const uploadResp = await fetch(uploadUrl, {
        method: 'PUT',

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Update the CLI (`pnpm update @mastra/cli` / latest version) so its expectations match the current API
  2. Verify you're hitting the intended platform endpoint/base URL (no stale MASTRA_BASE_URL or proxy override)
  3. Retry — if persistent, capture the raw response (debug logs) and check the platform API version/status
  4. Check platform service health/release notes for a deploy-create regression

Example fix

// check for stale endpoint config
// before
MASTRA_BASE_URL=https://old-internal-gw.example.com mastra server deploy
// after
unset MASTRA_BASE_URL && mastra server deploy  # use the current default API
Defensive patterns

Strategy: retry

Validate before calling

// Can't validate the server's response shape beforehand, but you can sanity-check
// the CLI/API pairing before deploying:
const cliVersion = (await exec('mastra --version')).trim();
console.log(`CLI ${cliVersion} against API ${process.env.MASTRA_BASE_URL ?? 'default'} — ensure platform is up to date`);

Type guard

type DeployCreateResponse = { id: string; status: string; uploadUrl?: string };
function hasUploadUrl(d: DeployCreateResponse): d is DeployCreateResponse & { uploadUrl: string } {
  return typeof d.uploadUrl === 'string' && d.uploadUrl.length > 0;
}

Try / catch

try {
  await deploy();
} catch (err) {
  if (err instanceof Error && err.message === 'No upload URL returned') {
    // API contract mismatch — upgrade CLI or check endpoint, then retry once
    await exec('pnpm update -g @mastra/cli');
    await deploy();
  } else throw err;
}

Prevention

When it happens

Trigger: Server (or a proxy/gateway intercepting the response) returns a 2xx deploy object without uploadUrl — e.g. unexpected API version drift, a mock/dev server stub, or a response transformed/stripped by middleware; typed as present in the schema but absent at runtime.

Common situations: Pointing the CLI at an older/self-hosted platform build whose create-deploy response omits uploadUrl; corporate proxy rewriting responses; API contract changed while CLI is outdated (or vice versa).

Related errors


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