mastra-ai/mastra · error · WorkItemRelationError
The related work item chain contains a cycle.
Error message
The related work item chain contains a cycle.
What it means
While walking up the parent chain from the proposed parent, validateParentRelation revisited an item it already visited, meaning the EXISTING data already contains a cycle unrelated to itemId. It throws WorkItemRelationError to signal corrupt/looping parent links.
Source
Thrown at mastracode/factory/src/storage/domains/work-items/base.ts:607
export function validateParentRelation(
projectItems: WorkItemRow[],
itemId: string | undefined,
parentWorkItemId: string | null,
): void {
if (parentWorkItemId === null) return;
const byId = new Map(projectItems.map(item => [item.id, item]));
const parent = byId.get(parentWorkItemId);
if (!parent) throw new WorkItemRelationError('Related work item not found in this project.');
if (itemId === parentWorkItemId) throw new WorkItemRelationError('A work item cannot relate to itself.');
const visited = new Set<string>();
let cursor: WorkItemRow | undefined = parent;
while (cursor?.parentWorkItemId) {
if (cursor.parentWorkItemId === itemId) {
throw new WorkItemRelationError('This relationship would create a cycle.');
}
if (visited.has(cursor.id)) throw new WorkItemRelationError('The related work item chain contains a cycle.');
visited.add(cursor.id);
cursor = byId.get(cursor.parentWorkItemId);
}
}
/**
* Diff `oldStages` → `newStages` and return the updated history: exited stages
* get `exitedAt` + `exitedBy` stamped on their open entry, entered stages get
* a new entry.
*/
export function applyStageTransition(
history: WorkItemStageEntry[],
oldStages: WorkItemStage[],
newStages: WorkItemStage[],
by: string,
now: Date,
): WorkItemStageEntry[] {
const timestamp = now.toISOString();View on GitHub (pinned to 75dd419e61)
Solutions
- Find and repair the existing cycle in stored work items (set one link's parentWorkItemId to null) before retrying
- Add a data-integrity audit that walks all parent chains and reports loops
- Catch WorkItemRelationError, log the offending chain, and surface it to an admin rather than end users
Example fix
// before
await workItems.update({ id, parentWorkItemId: brokenParentId }); // parent chain already loops
// after
await workItems.update({ id: loopingItemId, parentWorkItemId: null }); // break existing cycle first
await workItems.update({ id, parentWorkItemId: brokenParentId }); Defensive patterns
Strategy: validation
Validate before calling
function detectExistingCycle(items) {
for (const item of items) {
const seen = new Set();
let c = items.find(i => i.id === item.parentWorkItemId);
while (c) {
if (seen.has(c.id)) return c.id;
seen.add(c.id);
c = items.find(i => i.id === c.parentWorkItemId);
}
}
return null;
} Type guard
null
Try / catch
try {
await workItems.update({ id, parentWorkItemId });
} catch (e) {
if (e instanceof WorkItemRelationError && e.message.includes('chain contains a cycle')) {
// run data repair on stored parent links before retrying
} else throw e;
} Prevention
- Run periodic integrity audits over stored parent chains
- Fix migrations/seeds to never write looped parent pointers
- Break any detected cycle by nulling one link before new writes
When it happens
Trigger: Attempting any create/update with a parentWorkItemId whose existing ancestor chain is already looped (e.g. legacy data where A→B→A), regardless of the new link being valid.
Common situations: Databases seeded or migrated with inconsistent parent pointers, prior bugs that wrote cycles, or concurrent updates that created a loop before validation ran.
Related errors
- This relationship would create a cycle.
- Version-control installation not found.
- Bound Factory work item not found.
- Related work item not found in this project.
- A work item cannot relate to itself.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/660281f2bce8ecec.
Report an issue: GitHub.