{"record":{"id":"3f3d117f0f1849b7","repo":"mastra-ai/mastra","slug":"the-operation-was-aborted-3f3d11","errorCode":null,"errorMessage":"The operation was aborted.","messagePattern":"The operation was aborted\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"packages/memory/src/processors/observational-memory/retry.ts","lineNumber":182,"sourceCode":"  /** Optional abort signal — cancels both in-flight attempts and backoff waits. */\n  abortSignal?: AbortSignal;\n}\n\n/**\n * Run `fn` with retries on transient transport-class errors.\n *\n * Non-transient errors (auth, validation, schema, etc.) are rethrown\n * immediately. User-initiated aborts are rethrown without delay.\n *\n * @internal\n */\nexport async function withRetry<T>(fn: () => Promise<T>, opts: WithRetryOptions): Promise<T> {\n  const { label, abortSignal } = opts;\n  let attempt = 0;\n  // total tries = maxRetries + 1 (the initial attempt isn't a \"retry\")\n  while (true) {\n    if (abortSignal?.aborted) {\n      throw new Error('The operation was aborted.');\n    }\n    try {\n      return await fn();\n    } catch (error) {\n      if (isAbortError(error) || abortSignal?.aborted) throw error;\n      if (attempt >= RETRY_CONFIG.maxRetries || !isTransientLLMError(error)) {\n        if (attempt > 0) {\n          omDebug(\n            `[OM:retry:${label}] giving up after ${attempt} retry/retries: ${\n              error instanceof Error ? error.message : String(error)\n            }`,\n          );\n        }\n        throw error;\n      }\n      const delay = computeDelay(attempt);\n      attempt++;\n      omDebug(","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/retry.ts#L164-L200","documentation":"withRetry retries transient LLM failures up to RETRY_CONFIG.maxRetries and throws Error('The operation was aborted.') when the AbortSignal is already aborted before an attempt (or rethrows AbortErrors from fn). It stops retry loops promptly on cancellation instead of burning attempts.","triggerScenarios":"The abortSignal passed in opts is aborted before an attempt starts, or fn throws an AbortError / the signal aborts while awaiting fn, while generating reflector output (doGenerate).","commonSituations":"Request deadline exceeded during LLM retries; caller cancelled a long reflection; infrastructure-level timeouts propagating AbortSignals into the retry loop.","solutions":["Confirm the abort was intended (timeout/disconnect) via signal reason and logging","Increase the timeout that triggers the abort if reflections legitimately take longer","Retry the operation with a fresh, non-aborted signal","Catch and treat as cooperative cancellation in the caller"],"exampleFix":"// before\nconst signal = AbortSignal.timeout(30_000);\nawait withRetry(doGenerate, { label: 'reflect', abortSignal: signal });\n// after\nconst signal = AbortSignal.timeout(120_000); // raise budget\nawait withRetry(doGenerate, { label: 'reflect', abortSignal: signal });","handlingStrategy":"retry","validationCode":"if (opts.abortSignal?.aborted) skipOperation();","typeGuard":"const isAbortErr = (e: unknown) => e instanceof Error && (e.name === 'AbortError' || /aborted/i.test(e.message));","tryCatchPattern":"try { await withRetry(fn, opts) } catch (e) { if (opts.abortSignal?.aborted) return; throw e; }","preventionTips":["Set realistic timeouts before aborting LLM calls","Reuse a single cancellation scope per request","Log abort reasons for diagnosis"],"tags":["abort","retry","cancellation","llm"],"backgroundTag":"operation-aborted","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}