mastra-ai/mastra · error · RangeError

maxRetainedBytes must be a non-negative integer or Infinity

Error message

maxRetainedBytes must be a non-negative integer or Infinity

What it means

validateMaxRetainedProcessOutputBytes enforces that maxRetainedProcessOutputBytes is a non-negative integer or Infinity. Any NaN, fractional, negative, or non-numeric value (other than Infinity) throws this RangeError at ProcessHandle construction.

Source

Thrown at packages/core/src/workspace/sandbox/process-manager/process-handle.ts:22

 * Abstract base class for process handles.
 * Manages stdout/stderr callback dispatch and provides lazy
 * reader/writer stream getters — subclasses only implement
 * the platform-specific primitives.
 */

import { Readable, Writable } from 'node:stream';

import type { CommandResult } from '../types';
import type { SpawnProcessOptions } from './types';

export const DEFAULT_MAX_RETAINED_PROCESS_OUTPUT_BYTES = 1024 * 1024;
const RETAINED_OUTPUT_COMPACT_CHUNK_THRESHOLD = 128;

/** @internal */
export function validateMaxRetainedProcessOutputBytes(maxRetainedBytes: number): number {
  if (maxRetainedBytes === Infinity) return maxRetainedBytes;
  if (!Number.isFinite(maxRetainedBytes) || maxRetainedBytes < 0 || !Number.isInteger(maxRetainedBytes)) {
    throw new RangeError('maxRetainedBytes must be a non-negative integer or Infinity');
  }
  return maxRetainedBytes;
}

function advanceStartByUtf8Bytes(
  value: string,
  start: number,
  minimumBytesToDrop: number,
): { start: number; droppedBytes: number } {
  let nextStart = start;
  let droppedBytes = 0;

  while (nextStart < value.length && droppedBytes < minimumBytesToDrop) {
    const codePoint = value.codePointAt(nextStart)!;

    if (codePoint < 0x80) droppedBytes += 1;
    else if (codePoint < 0x800) droppedBytes += 2;
    else if (codePoint < 0x10000) droppedBytes += 3;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass a non-negative integer (e.g. 5 * 1024 * 1024) or Infinity.
  2. Coerce string config values with Number()/parseInt before passing.
  3. Round computed limits with Math.floor().

Example fix

// before
new ProcessHandle({ maxRetainedProcessOutputBytes: opts.retainedOutput }); // '5242880' string
// after
const n = Number(opts.retainedOutput);
new ProcessHandle({
  maxRetainedProcessOutputBytes: Number.isFinite(n) ? Math.max(0, Math.floor(n)) : Infinity,
});
Defensive patterns

Strategy: validation

Validate before calling

function isValidRetainedBytes(v: unknown): v is number {
  return v === Infinity || (typeof v === 'number' && Number.isInteger(v) && v >= 0);
}
if (!isValidRetainedBytes(opts.maxRetainedProcessOutputBytes)) {
  throw new TypeError('maxRetainedProcessOutputBytes must be a non-negative integer or Infinity');
}

Type guard

function isNonNegIntOrInfinity(v: unknown): v is number {
  return v === Infinity || (typeof v === 'number' && Number.isSafeInteger(v) && v >= 0);
}

Try / catch

try {
  handle = new ProcessHandle({ maxRetainedProcessOutputBytes: raw });
} catch (e) {
  if (e instanceof RangeError && /maxRetainedBytes/.test(e.message)) {
    handle = new ProcessHandle({ maxRetainedProcessOutputBytes: 1024 * 1024 });
  } else throw e;
}

Prevention

When it happens

Trigger: Constructing a ProcessHandle (or passing a process option) with e.g. maxRetainedBytes: -1, 10.5, '1MB', NaN, or null.

Common situations: Parsing a config value from env/CLI as a string instead of a number; computing a byte limit with arithmetic that yields a float (e.g. bytes = 0.5 * MB); typos like `1024 * 1024,` producing a non-integer expression result.

Understand the failure class

Background: "must be positive", "Invalid value": how libraries reject invalid parameter values (ValueError, ArgumentError, INVALID_PARAMETER_VALUE) — this error's family across 28 libraries.

Related errors


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