mastra-ai/mastra · error

stdout backpressure exceeded the experiment deadline

Error message

stdout backpressure exceeded the experiment deadline

What it means

The experiment worker writes NDJSON protocol frames to stdout and, when the stream buffer is full (write() returned false), waits for 'drain' with an AbortController tied to the run deadline. If the deadline fires before stdout drains, the wait is aborted and this error is thrown, which is then wrapped into a ProtocolOutputError. It means the consumer of the worker's stdout stopped reading (or was too slow) for so long that the experiment's time budget expired mid-write.

Source

Thrown at packages/cli/src/commands/experiment/runtime.ts:385

    };
  };
  const abortForProtocolFailure = (message: string) => {
    if (protocolFailure || terminal) return;
    protocolFailure = new Error(message);
    report(message);
    controller?.abort(protocolFailure);
  };
  const waitForDrain = async () => {
    const drainController = new AbortController();
    let deadlineExceeded = false;
    const clearTimer = scheduleAtDeadline(() => {
      deadlineExceeded = true;
      drainController.abort();
    });
    try {
      await once(stdout, 'drain', { signal: drainController.signal });
    } catch (error) {
      if (deadlineExceeded) throw new Error('stdout backpressure exceeded the experiment deadline');
      throw error;
    } finally {
      clearTimer();
      drainController.abort();
    }
  };
  const writeEvent = (type: string, payload: Record<string, unknown>) => {
    if (!correlation || terminal || (finishing && type !== 'terminal') || (type === 'heartbeat' && heartbeatQueued)) {
      return writeTail;
    }
    const event = {
      ...correlation,
      eventId: createEventId(),
      sequence,
      emittedAt: now().toISOString(),
      type,
      payload,
    };

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure the parent process continuously reads/consumes the worker's stdout (don't pause or block the pipe reader).
  2. Increase the experiment deadline if runs legitimately produce large output volumes.
  3. Reduce output volume (fewer/smaller events, larger heartbeat intervals) to lower backpressure.
  4. Check where stdout is redirected — writing to a full disk or a stalled collector is a common cause.

Example fix

// before (parent)
child.spawn(...); // stdout never read -> pipe fills
// after
child.stdout.on('data', frame => handleFrame(frame)); // drain continuously
Defensive patterns

Strategy: try-catch

Validate before calling

// before starting the worker, ensure a continuous stdout consumer exists
child.stdout.on('data', () => {}); // or wire a real frame parser; never leave the pipe unread

Type guard

null

Try / catch

try {
  const frames = await runExperimentWorker({ mastra, runExperiment, build });
} catch (e) {
  if (e instanceof Error && e.message.includes('backpressure exceeded the experiment deadline')) {
    // retry with a longer deadline or a lighter-output run
  } else throw e;
}

Prevention

When it happens

Trigger: stdout.write() returns false (backpressure) and once(stdout,'drain') is aborted by the deadline timer before the pipe consumer drains the stream — e.g. the parent process is paused, blocked, or reading too slowly while the run deadline elapses.

Common situations: Parent CLI/runner blocked on something else and not consuming stdout; output redirected to a full or slow disk/file; downstream log collector stalled; a very chatty experiment emitting large frames faster than the consumer reads, combined with a tight deadline.

Related errors


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