mastra-ai/mastra · error · WorkItemRelationError
A work item cannot relate to itself.
Error message
A work item cannot relate to itself.
What it means
Work items cannot be their own parent. validateParentRelation compares itemId to parentWorkItemId and throws WorkItemRelationError when a create/update would make an item relate to itself.
Source
Thrown at mastracode/factory/src/storage/domains/work-items/base.ts:599
function priorState(row: WorkItemDbRow): WorkItemPriorState {
return { stages: row.stages, sessionRoles: Object.keys(row.sessions) };
}
export class WorkItemRelationError extends Error {
readonly code = 'invalid_work_item_relation';
}
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.
*/View on GitHub (pinned to 75dd419e61)
Solutions
- Guard before the call: skip or reject when parentWorkItemId === itemId
- In UI code, exclude the current item from the parent picker options
- Catch WorkItemRelationError and show a validation message instead of retrying
Example fix
// before
await workItems.update({ id, parentWorkItemId: parentId });
// after
if (parentId !== id) {
await workItems.update({ id, parentWorkItemId: parentId });
} Defensive patterns
Strategy: validation
Validate before calling
if (parentWorkItemId === itemId) throw new Error('A work item cannot be its own parent'); Type guard
null
Try / catch
try {
await workItems.update({ id, parentWorkItemId });
} catch (e) {
if (e instanceof WorkItemRelationError && e.message.includes('relate to itself')) {
// reject the form submission / fix the payload
} else throw e;
} Prevention
- Exclude the current item from parent-selection UI options
- Strip self-references in sync/import code before writing parentWorkItemId
- Add a unit test asserting self-parenting is rejected
When it happens
Trigger: Calling workItems create or update with parentWorkItemId equal to the item's own id (or the id being upserted).
Common situations: Form/UI round-trips where the item's own id is accidentally submitted as its parent, bulk sync code that copies parentId without excluding self, or patching an item after it was promoted to a parent.
Related errors
- Related work item not found in this project.
- [FilesystemStorage] resourceId must not be empty.
- This relationship would create a cycle.
- The related work item chain contains a cycle.
- EXPERIMENT_RESULT_MISSING_EXPERIMENT_ID
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/fdb80f2568ad72b3.
Report an issue: GitHub.