mastra-ai/mastra · warning

The operation was aborted.

Error message

The operation was aborted.

What it means

The Reflector runner (which runs the Reflector agent that consolidates observations) defines its own module-level `withAbortCheck` helper that throws this error both before and after the wrapped operation if the caller's AbortSignal is aborted (reflector-runner.ts:158). Throwing at :158 means the signal was already aborted when the reflector step was about to run, so the library cancels reflection instead of executing a doomed model call.

Source

Thrown at packages/memory/src/processors/observational-memory/reflector-runner.ts:158

    if (model) {
      return model;
    }
  }

  return undefined;
}

type ConcreteReflectionModel = Exclude<ResolvedReflectionConfig['model'], ModelByInputTokens>;

type ReflectionModelResolver = (inputTokens: number) => {
  model: ConcreteReflectionModel;
  selectedThreshold?: number;
  routingStrategy?: 'model-by-input-tokens';
  routingThresholds?: string;
};

async function withAbortCheck<T>(fn: () => Promise<T>, abortSignal?: AbortSignal): Promise<T> {
  if (abortSignal?.aborted) throw new Error('The operation was aborted.');
  const result = await fn();
  if (abortSignal?.aborted) throw new Error('The operation was aborted.');
  return result;
}

/**
 * Minimum size of combined (buffered reflection + unreflected tail) expressed
 * as a ratio of the regular threshold-activation target
 * (reflectThreshold × (1 − bufferActivation)). Early TTL / provider-change
 * triggers are suppressed if the post-activation size would fall below this
 * floor — keeps early activations close to the system's tuned post-activation
 * size while still letting them fire sooner than a threshold activation.
 */
const EARLY_ACTIVATION_SIZE_FLOOR_RATIO = 0.75;

/**
 * Result of an attempt to activate a buffered reflection. The caller uses
 * this to decide whether to fall through to sync reflection or background

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check `signal.aborted` before starting the memory pipeline and skip processing entirely rather than entering a phase that will throw.
  2. Give each phase its own AbortController (or use `AbortSignal.any` with only relevant sources) so an abort during Observer doesn't poison the Reflector phase entry.
  3. Extend timeouts to cover the full pipeline (observer + reflector), or run reflection asynchronously/detached from the request lifecycle so request cancellation doesn't abort it.
  4. Catch and treat this as benign cancellation in the memory-processing caller; optionally log token savings from the skipped reflection.

Example fix

// before
await agent.generate(messages, {
  abortSignal: req.signal, // aborted during observer phase; reflector throws immediately
});

// after
const memoryController = new AbortController();
req.signal.addEventListener('abort', () => memoryController.abort(), { once: true });
// or run reflection detached:
void memory.process(messages, { abortSignal: memoryController.signal }).catch(err => {
  if ((err as Error).message !== 'The operation was aborted.') console.error(err);
});
Defensive patterns

Strategy: try-catch

Validate before calling

if (signal?.aborted) {
  // skip the memory pipeline entirely before the reflector phase can throw
  return skipProcessing();
}

Type guard

function isAbortError(err: unknown): err is Error {
  return err instanceof Error && err.message === 'The operation was aborted.';
}

Try / catch

try {
  await runAgentWithMemory(input, { abortSignal: controller.signal });
} catch (err) {
  if (isAbortError(err)) return; // cancelled before/during reflection; benign
  throw err;
}

Prevention

When it happens

Trigger: The AbortSignal passed into memory processing is already aborted when the Reflector phase (`result`, which wraps its generation in `withAbortCheck`) begins — e.g. the request was cancelled during the preceding Observer phase, and the same signal is checked before reflection starts.

Common situations: Client disconnects or request timeout fires during the Observer phase, so by the time Reflector runs the shared signal is dead; reusing one AbortController across sequential memory phases; calling memory APIs with `AbortSignal.timeout` shorter than observer+reflector combined runtime; passing an already-settled request's signal.

Related errors


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