mastra-ai/mastra · error

Sandbox provider "${sandbox.provider}" did not expose a publ

Error message

Sandbox provider "${sandbox.provider}" did not expose a public URL for port ${port}. Make sure the port is declared when constructing the sandbox (e.g. `ports: [${port}]`).

What it means

After capability checks pass, deployToSandbox requests the provider's public URL for the deploy port. If getPortUrl returns null/undefined — typically because the port wasn't declared at sandbox construction — the deploy cannot continue and this error is thrown.

Source

Thrown at deployers/sandbox/src/engine.ts:81

  // 1. Start (providers handle create-or-resume by identity, e.g. sandbox name).
  logger.info(`Starting ${sandbox.provider} sandbox...`);
  await sandbox.start?.();

  if (!supportsNetworking(sandbox)) {
    throw new Error(
      `Sandbox provider "${sandbox.provider}" does not support networking (public port URLs), ` +
        `which is required for sandbox deploys.`,
    );
  }
  if (!sandbox.executeCommand) {
    throw new Error(
      `Sandbox provider "${sandbox.provider}" does not support executeCommand, which is required for sandbox deploys.`,
    );
  }

  const url = await sandbox.networking.getPortUrl(port);
  if (!url) {
    throw new Error(
      `Sandbox provider "${sandbox.provider}" did not expose a public URL for port ${port}. ` +
        `Make sure the port is declared when constructing the sandbox (e.g. \`ports: [${port}]\`).`,
    );
  }

  // Default the remote dir to $HOME/mastra-app — home directories persist
  // across snapshot stop/resume (unlike /tmp), so wakes find the app intact.
  const remoteDir = await resolveRemoteDir(sandbox, options.remoteDir);

  const mergedEnv = { ...env };
  if (studio && mergedEnv.MASTRA_STUDIO_PATH === undefined) {
    mergedEnv.MASTRA_STUDIO_PATH = `${remoteDir}/studio`;
  }

  // 2. Upload the build output as a tarball and extract it in the sandbox.
  logger.info(`Uploading build output from ${dir}...`);
  const tarball = await createTarball(dir);
  logger.debug(`Tarball size: ${(tarball.length / 1024 / 1024).toFixed(2)} MB`);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Declare the port at sandbox construction: `ports: [port]`
  2. Make the port passed to deployToSandbox match a declared port
  3. Recreate the sandbox so newly declared ports are provisioned
  4. Log/inspect all provider-exposed URLs to confirm the expected port exists

Example fix

// before
const sandbox = new Sandbox({ ports: [] });
await deployToSandbox(sandbox, { port: 8788 });
// after
const sandbox = new Sandbox({ ports: [8788] });
await deployToSandbox(sandbox, { port: 8788 });
Defensive patterns

Strategy: validation

Validate before calling

if (!ports.includes(port)) {
  throw new Error(`Port ${port} must be declared at sandbox construction: ports: [${port}]`);
}

Try / catch

try {
  await deployToSandbox(sandbox, { port });
} catch (err) {
  if (String(err).includes('did not expose a public URL')) {
    console.error(`recreate the sandbox with ports: [${port}]`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling deployToSandbox while the provider's networking.getPortUrl(port) returns null: the requested port is not in the sandbox's declared `ports`, or the provider hasn't provisioned a URL for it.

Common situations: Deploying on a custom PORT without declaring it in ports at sandbox creation; provider allocates URLs lazily and the port was declared after sandbox creation; typo'd port number mismatch between deploy options and sandbox config.

Related errors


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