{"record":{"id":"6f7aa93de6e4387e","repo":"mastra-ai/mastra","slug":"cannot-rehydrate-conditional-step-missing-or-mism","errorCode":null,"errorMessage":"Cannot rehydrate conditional step: missing or mismatched predicates. Only declarative predicate branches round-trip.","messagePattern":"Cannot rehydrate conditional step: missing or mismatched predicates\\. Only declarative predicate branches round-trip\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/workflows/dynamic/rehydrate.ts","lineNumber":160,"sourceCode":"    case 'step': {\n      const live = rehydrateSingleEntry(entry, mastra, schemaOpts);\n      wf.__pushStepFlowEntry(live, entry);\n      return;\n    }\n    case 'workflow': {\n      const nested = assertWorkflowExists(mastra, entry.workflowId);\n      // A nested workflow executes as its own `Workflow`, so the engine keys its\n      // result by the workflow's intrinsic id. The portable definition addresses\n      // it by the declared call-site id, which is what mappings, predicates and\n      // `${stepResults...}` templates reference. Clone it under the declared id so\n      // every reference resolves instead of silently falling back to `initData`.\n      wf.then(entry.id && entry.id !== nested.id ? cloneWorkflow(nested as any, { id: entry.id }) : nested);\n      return;\n    }\n    case 'conditional': {\n      const predicates = entry.predicates;\n      if (!predicates || predicates.length !== entry.steps.length || predicates.some(p => !p)) {\n        throw new Error(\n          `Cannot rehydrate conditional step: missing or mismatched predicates. Only declarative predicate branches round-trip.`,\n        );\n      }\n      const steps = entry.steps.map(s => rehydrateSingleEntry(s, mastra, schemaOpts));\n      // Wire graphs may omit the Studio-facing condition labels; derive them\n      // from the predicates (same convention as the fluent builder).\n      const serializedConditions =\n        entry.serializedConditions ??\n        steps.map((s, i) => ({ id: `${getSingleStepEntryId(s)}-condition`, fn: derivePredicateLabel(predicates[i]!) }));\n      const live: StepFlowEntry = {\n        type: 'conditional',\n        steps,\n        conditions: predicates.map(p => predicateToCondition(p!)),\n        serializedConditions,\n        predicates,\n      };\n      wf.__pushStepFlowEntry(live, { ...entry, serializedConditions });\n      return;","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workflows/dynamic/rehydrate.ts#L142-L178","documentation":"When rehydrating a stored dynamic workflow graph, a 'conditional' entry must carry a `predicates` array that is present, the same length as `entry.steps`, and contains no null/undefined entries. Predicates are the declarative branch conditions attached to each branch of a conditional step; non-declarative (function-based or missing) predicates cannot be serialized, so the stored graph cannot be round-tripped. The library throws instead of silently dropping branches, because rehydrating a conditional without its predicates would change runtime behavior.","triggerScenarios":"Calling rehydrateWorkflow with a stored graph entry whose `type === 'conditional'` where: entry.predicates is undefined/null, entry.predicates.length !== entry.steps.length, or any predicate element is falsy (p => !p). This happens when the workflow was built with non-declarative predicates (inline functions) that could not be serialized, or when the stored graph was hand-edited/partially persisted.","commonSituations":"Restoring a persisted dynamic workflow (e.g. from a database or stored graph JSON) whose conditional branches were defined with function predicates instead of the declarative condition builder; a serialization version that predates predicate persistence; manually edited stored graphs where a branch was added without adding its predicate.","solutions":["Rebuild the workflow using the declarative conditional API (createWorkflow branch/condition builders) so predicates serialize, then re-persist the graph.","Check the stored graph JSON: ensure `predicates` exists on the conditional entry, has exactly one predicate per entry in `steps`, and no null entries.","If migrating from an older stored format, re-export/re-serialize the workflow with the current serializer version before rehydrating.","If branches are inherently dynamic (functions), keep the workflow defined in code rather than storing/rehydrating it."],"exampleFix":"// stored entry (broken)\n{ type: 'conditional', steps: [stepA, stepB] } // predicates missing\n\n// fixed stored entry\n{ type: 'conditional', steps: [stepA, stepB], predicates: [serializedConditionA, serializedConditionB] }","handlingStrategy":"validation","validationCode":"function hasRoundTrippablePredicates(entry) {\n  return entry.type !== 'conditional' ||\n    (Array.isArray(entry.predicates) &&\n     entry.predicates.length === entry.steps.length &&\n     entry.predicates.every(Boolean));\n}\n// run over stored graph entries before rehydrateWorkflow","typeGuard":"function isConditionalEntry(e: unknown): e is { type: 'conditional'; steps: unknown[]; predicates: unknown[] } {\n  return typeof e === 'object' && e !== null && (e as any).type === 'conditional' &&\n    Array.isArray((e as any).predicates);\n}","tryCatchPattern":"try {\n  const wf = rehydrateWorkflow(stored, mastra);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('Cannot rehydrate conditional step')) {\n    // fall back to rebuilding the workflow from source definition\n  }\n  throw err;\n}","preventionTips":["Always use the declarative condition builders for conditional branches, never inline function predicates.","Re-serialize stored graphs after upgrading the library rather than reusing old persisted JSON.","Validate stored graph JSON (predicates present, aligned with steps) before rehydration."],"tags":["workflow","serialization","rehydration","conditional"],"backgroundTag":"workflow-rehydration-unsupported-predicate","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}