mastra-ai/mastra · error · WorkItemRelationError

Related work item not found in this project.

Error message

Related work item not found in this project.

What it means

validateParentRelation checks that any parent (related) work item passed to create/update actually exists within the same project. If parentWorkItemId does not match any item in the project's item list, WorkItemRelationError is thrown so no dangling cross-project or nonexistent relation is stored.

Source

Thrown at mastracode/factory/src/storage/domains/work-items/base.ts:598

}

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

  1. Fetch the parent item first within the same project and confirm it exists before linking
  2. Verify the parentWorkItemId belongs to the same projectId as the child
  3. Handle WorkItemRelationError in the caller and surface a user-facing 'parent not found' message
  4. Re-query the project's work items if the parent was recently created (stale cache)

Example fix

// before
await workItems.update({ id: childId, parentWorkItemId: 'item-999' });
// after
const parent = await workItems.get({ projectId, id: 'item-999' });
if (!parent) throw new Error('Parent item not found in this project');
await workItems.update({ id: childId, parentWorkItemId: 'item-999' });
Defensive patterns

Strategy: validation

Validate before calling

const parent = projectItems.find(i => i.id === parentWorkItemId);
if (!parent) throw new Error(`Parent ${parentWorkItemId} not found in project ${projectId}`);

Type guard

null

Try / catch

try {
  await workItems.update({ id, parentWorkItemId });
} catch (e) {
  if (e instanceof WorkItemRelationError && e.message.includes('not found in this project')) {
    // surface 'parent not found' to user / pick a valid parent
  } else throw e;
}

Prevention

When it happens

Trigger: Calling workItems create/update/#upsert with a parentWorkItemId that references a work item from another project, a deleted item, or a typo'd/nonexistent ID.

Common situations: Copy-pasting item IDs across projects, a parent item deleted before the child update is applied, or IDs coming from a different tenant/org context.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/b83083b2cda01d24. Report an issue: GitHub.