{"record":{"id":"408dbc88b95cbd97","repo":"mastra-ai/mastra","slug":"the-operation-was-aborted-408dbc","errorCode":null,"errorMessage":"The operation was aborted.","messagePattern":"The operation was aborted\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/memory/src/processors/observational-memory/reflector-runner.ts","lineNumber":158,"sourceCode":"    if (model) {\n      return model;\n    }\n  }\n\n  return undefined;\n}\n\ntype ConcreteReflectionModel = Exclude<ResolvedReflectionConfig['model'], ModelByInputTokens>;\n\ntype ReflectionModelResolver = (inputTokens: number) => {\n  model: ConcreteReflectionModel;\n  selectedThreshold?: number;\n  routingStrategy?: 'model-by-input-tokens';\n  routingThresholds?: string;\n};\n\nasync function withAbortCheck<T>(fn: () => Promise<T>, abortSignal?: AbortSignal): Promise<T> {\n  if (abortSignal?.aborted) throw new Error('The operation was aborted.');\n  const result = await fn();\n  if (abortSignal?.aborted) throw new Error('The operation was aborted.');\n  return result;\n}\n\n/**\n * Minimum size of combined (buffered reflection + unreflected tail) expressed\n * as a ratio of the regular threshold-activation target\n * (reflectThreshold × (1 − bufferActivation)). Early TTL / provider-change\n * triggers are suppressed if the post-activation size would fall below this\n * floor — keeps early activations close to the system's tuned post-activation\n * size while still letting them fire sooner than a threshold activation.\n */\nconst EARLY_ACTIVATION_SIZE_FLOOR_RATIO = 0.75;\n\n/**\n * Result of an attempt to activate a buffered reflection. The caller uses\n * this to decide whether to fall through to sync reflection or background","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/reflector-runner.ts#L140-L176","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check `signal.aborted` before starting the memory pipeline and skip processing entirely rather than entering a phase that will throw.","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.","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.","Catch and treat this as benign cancellation in the memory-processing caller; optionally log token savings from the skipped reflection."],"exampleFix":"// before\nawait agent.generate(messages, {\n  abortSignal: req.signal, // aborted during observer phase; reflector throws immediately\n});\n\n// after\nconst memoryController = new AbortController();\nreq.signal.addEventListener('abort', () => memoryController.abort(), { once: true });\n// or run reflection detached:\nvoid memory.process(messages, { abortSignal: memoryController.signal }).catch(err => {\n  if ((err as Error).message !== 'The operation was aborted.') console.error(err);\n});","handlingStrategy":"try-catch","validationCode":"if (signal?.aborted) {\n  // skip the memory pipeline entirely before the reflector phase can throw\n  return skipProcessing();\n}","typeGuard":"function isAbortError(err: unknown): err is Error {\n  return err instanceof Error && err.message === 'The operation was aborted.';\n}","tryCatchPattern":"try {\n  await runAgentWithMemory(input, { abortSignal: controller.signal });\n} catch (err) {\n  if (isAbortError(err)) return; // cancelled before/during reflection; benign\n  throw err;\n}","preventionTips":["Use a single AbortController owned by the pipeline so abort timing is deliberate.","Budget timeouts for observer + reflector combined, not just one phase.","Run reflection detached from request lifecycle when memory updates should survive cancellations.","Check `signal.aborted` at phase boundaries and short-circuit gracefully."],"tags":["abortsignal","cancellation","reflector","observational-memory"],"backgroundTag":"operation-aborted","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}