{"record":{"id":"a24a85fcc4e84666","repo":"mastra-ai/mastra","slug":"result-as-any-error-message-workflow-recove","errorCode":null,"errorMessage":"(result as any).error?.message || 'Workflow recover failed'","messagePattern":"\\(result as any\\)\\.error\\?\\.message \\|\\| 'Workflow recover failed'","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/agent/durable/durable-agent.ts","lineNumber":2475,"sourceCode":"        );\n        recoveryLease.assertOwned();\n        const result = await this.#raceRecoveryLease(\n          run.restart({\n            requestContext,\n            ...createObservabilityContext({ currentSpan: recoverAgentSpan }),\n          } as any),\n          recoveryLease,\n        );\n        recoveryLease.assertOwned();\n        // Snapshot cleanup runs for every non-suspended terminal (success or\n        // failed) so storage stays bounded — mirrors the start()/resume()\n        // contract.\n        if (result?.status && result.status !== 'suspended') {\n          await this.deleteRunSnapshots(runId);\n          recoveryLease.assertOwned();\n        }\n        if (result?.status === 'failed') {\n          throw new Error((result as any).error?.message || 'Workflow recover failed');\n        }\n      })\n      .catch(async error => {\n        const leaseLossError = recoveryLease.getLossError();\n        if (leaseLossError) {\n          await threadRegistration?.rollback({ releaseLease: false });\n          streamCleanup();\n          cleanupOwnedRegistryState();\n        }\n        const recoveryError = leaseLossError ?? error;\n        const reported = await this.#reportRecoveryFailure(runId, recoveryError);\n        if (!reported && !leaseLossError) {\n          await threadRegistration?.rollback();\n          streamCleanup();\n          cleanupOwnedRegistryState();\n        }\n        throw recoveryError;\n      })","sourceCodeStart":2457,"sourceCodeEnd":2493,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/agent/durable/durable-agent.ts#L2457-L2493","documentation":"After a recover() workflow attempt reaches a terminal (non-suspended) status, snapshots are deleted; if that status is 'failed', the raw workflow error message is surfaced via `throw new Error((result as any).error?.message || 'Workflow recover failed')` at durable-agent.ts:2475. The fallback text appears when the workflow result carries status 'failed' but no readable error.message.","triggerScenarios":"The recovered workflow run fails during resume (model call error, step throw, abort handling) and result.error is undefined or lacks .message; a step inside the durable agentic loop throws a non-Error value so no message survives serialization.","commonSituations":"LLM provider outage or auth failure during recovery; a tool throwing a string instead of an Error; snapshot rehydration succeeding but execution failing immediately after; hitting this after a crash-recovery when underlying credentials expired.","solutions":["Inspect server logs/traces for the underlying workflow step failure — the true cause precedes this wrapper.","Throw Error objects (not strings/objects) inside tools and steps so message survives into result.error.","Check model provider credentials and network reachability before retrying recover().","Retry recover() once the underlying cause is fixed; snapshots were deleted only for finished terminal runs, so verify run state first."],"exampleFix":"// before\nthrow 'rate limit exceeded'; // inside a tool -> opaque 'Workflow recover failed'\n// after\nthrow new Error('rate limit exceeded');","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await agent.recover(runId);\n} catch (e) {\n  if (String(e) === 'Workflow recover failed') {\n    // underlying step error was lost: check workflow traces/logs for root cause\n  } else {\n    // e.message carries the real workflow failure\n    logger.error('recover failed', { cause: (e as Error).message });\n  }\n}","preventionTips":["Throw Error instances (not strings) inside tools and workflow steps.","Monitor provider credentials/health before invoking recover().","Inspect traces on the durable agentic-loop workflow for the root failure."],"tags":["durable-agent","recover","workflow-failed","error-wrapping"],"backgroundTag":"workflow-recover-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}