{"record":{"id":"bb51dc23956fcfaa","repo":"mastra-ai/mastra","slug":"dynamic-workflow-bundle-has-a-circular-nested-work","errorCode":null,"errorMessage":"Dynamic workflow bundle has a circular nested-workflow dependency among: ${Array.from(remaining.keys()).sort().join(', ')}.","messagePattern":"Dynamic workflow bundle has a circular nested-workflow dependency among: (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/mastra/index.ts","lineNumber":5031,"sourceCode":"    const ordered: typeof members = [];\n    const remaining = new Map(members.map(member => [member.normalized.id, member] as const));\n    const hydrated = new Set<string>();\n    let progress = true;\n    while (remaining.size > 0 && progress) {\n      progress = false;\n      for (const [id, member] of Array.from(remaining)) {\n        const pending = Array.from(collectNestedWorkflowIds(member.normalized.graph)).filter(\n          dependency => dependency !== id && bundleIds.has(dependency) && !hydrated.has(dependency),\n        );\n        if (pending.length > 0) continue;\n        remaining.delete(id);\n        hydrated.add(id);\n        ordered.push(member);\n        progress = true;\n      }\n    }\n    if (remaining.size > 0) {\n      throw new Error(\n        `Dynamic workflow bundle has a circular nested-workflow dependency among: ${Array.from(remaining.keys())\n          .sort()\n          .join(', ')}.`,\n      );\n    }\n\n    // Snapshot the registry slots this bundle will overwrite so a failure\n    // anywhere below leaves the instance exactly as it was found.\n    const registry = this.#workflows as Record<string, AnyWorkflow>;\n    const priorWorkflows = new Map<string, AnyWorkflow | undefined>();\n    const priorHiddenKeys = new Set<string>();\n    for (const { normalized } of ordered) {\n      priorWorkflows.set(normalized.id, registry[normalized.id]);\n      if (this.#hiddenWorkflowKeys.has(normalized.id)) priorHiddenKeys.add(normalized.id);\n    }\n    const restoreRegistry = () => {\n      for (const [id, prior] of priorWorkflows) {\n        if (prior) registry[id] = prior;","sourceCodeStart":5013,"sourceCodeEnd":5049,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/mastra/index.ts#L5013-L5049","documentation":"Dynamic workflow bundles are hydrated in topological order: each pass registers members whose nested workflows are already hydrated. If a full pass registers nothing yet members remain, their nested-workflow references form a cycle that can never resolve, and Mastra throws this plain Error listing the ids still unresolved.","triggerScenarios":"Registering a bundle where workflow A nests workflow B and B nests (or references) A, directly or through a longer chain — e.g. A -> B -> C -> A — so no member's dependencies are ever satisfied.","commonSituations":"Two team workflows calling each other for shared steps; a refactor turning a one-way call into a mutual one; copy/paste wiring the parent id into a child by mistake; self-nesting a workflow inside itself.","solutions":["Break the cycle: extract the shared steps into a third workflow that both A and B nest, so dependencies go one way.","Flatten the mutual recursion by inlining one direction's steps instead of calling back.","Inspect the ids listed in the message and draw the nesting graph to find the exact loop, then remove one edge.","If the recursion is intentional, restructure into an iterative loop inside a single workflow rather than nested workflow references."],"exampleFix":"// before\ndefs = [\n  { id: 'order', nested: ['payment'] },\n  { id: 'payment', nested: ['order'] }, // cycle\n];\n// after\ndefs = [\n  { id: 'validate', nested: [] },\n  { id: 'order', nested: ['validate', 'payment'] },\n  { id: 'payment', nested: ['validate'] },\n];","handlingStrategy":"validation","validationCode":"function assertAcyclic(defs) {\n  const deps = new Map(defs.map(d => [d.id, d.nested ?? []]));\n  const state = new Map();\n  const visit = id => {\n    if (state.get(id) === 'visiting') throw new Error(`Cycle involving workflow \"${id}\"`);\n    if (state.get(id) === 'done') return;\n    state.set(id, 'visiting');\n    for (const n of deps.get(id) ?? []) visit(n);\n    state.set(id, 'done');\n  };\n  for (const id of deps.keys()) visit(id);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await registerDynamicWorkflowBundle(defs);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Dynamic workflow bundle has a circular nested-workflow dependency')) {\n    console.error('Fix the nesting cycle among:', e.message);\n  } else throw e;\n}","preventionTips":["Run a topological-sort check on nested-workflow references before bundling.","Extract shared steps into a common child workflow instead of mutual nesting.","Never nest a workflow inside itself or a descendant."],"tags":["workflow","circular-dependency","validation"],"backgroundTag":"circular-dependency","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}