mastra-ai/mastra · error

Relaunch requires a new executionId.

Error message

Relaunch requires a new executionId.

What it means

relaunch() on a worker deployment creates a brand-new execution, so the caller must supply a fresh executionId. Supplying the same executionId as the current deployment would collide with the existing execution's paths/state, so the library rejects it upfront.

Source

Thrown at deployers/sandbox/src/worker.ts:413

    cancel: () => cancelExecution(config, executionId, resolvePaths),
    stop: async () => {
      if (!config.sandbox.stop) throw new Error(`Sandbox provider "${config.sandbox.provider}" does not support stop.`);
      await config.sandbox.stop();
    },
    destroy: options => destroyWithRetry(config.sandbox, options),
  };
}

function deployment(
  config: WorkerConfig,
  executionId: string,
  sandboxId: string,
  expiresAt?: Date,
): SandboxWorkerDeployment {
  return {
    ...execution(config, executionId, sandboxId, expiresAt),
    relaunch: async options => {
      if (options.executionId === executionId) throw new Error('Relaunch requires a new executionId.');
      validateInput(options.input);
      return createExecution(config, options.executionId, options.input);
    },
  };
}

async function stageInput(
  config: WorkerConfig,
  paths: ReturnType<typeof executionPaths>,
  input?: SandboxWorkerInput,
): Promise<string | undefined> {
  if (!input) return undefined;
  const data = typeof input.data === 'string' ? Buffer.from(input.data) : Buffer.from(input.data);
  if (data.byteLength > config.inputLimitBytes) {
    throw new Error(`Worker input exceeds inputLimitBytes (${data.byteLength} > ${config.inputLimitBytes}).`);
  }
  const path = input.type === 'stdin' ? paths.stdin : posix.resolve(config.remoteDir, input.path);
  await uploadFile(config.sandbox, path, data);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Generate a new unique executionId (e.g. crypto.randomUUID()) for each relaunch call.
  2. If you intended a retry of the same logical run, treat the new executionId as the retry's id — the library has no same-id retry path.
  3. Check your persistence layer for stale execution ids being passed back on relaunch.

Example fix

// before
await worker.relaunch({ executionId, input });
// after
await worker.relaunch({ executionId: crypto.randomUUID(), input });
Defensive patterns

Strategy: validation

Validate before calling

function assertNewExecutionId(currentId, nextId) {
  if (!nextId || nextId === currentId) throw new Error('relaunch requires a fresh executionId');
}

Type guard

function isFreshExecutionId(currentId, options) { return typeof options?.executionId === 'string' && options.executionId.length > 0 && options.executionId !== currentId; }

Try / catch

try {
  await worker.relaunch({ executionId: newId, input });
} catch (e) {
  if (/Relaunch requires a new executionId/.test(e.message)) {
    throw new Error('caller bug: reuse of executionId in relaunch');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling deployment.relaunch({ executionId, input }) where options.executionId === the executionId the deployment was created with.

Common situations: Reusing a stored/derived executionId (e.g. from the original deploy record) when relaunching; retry loops that forget to generate a new id; copy-pasted relaunch options.

Related errors


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