mastra-ai/mastra · error

Factory project is required

Error message

Factory project is required

What it means

The attention receipt mutation (read/archive/restore) requires a `factoryProjectId` to know which project's attention items to update. If the hook is invoked without one, it throws immediately in the mutation function rather than issuing a malformed API call.

Source

Thrown at mastracode/factory-ui/src/hooks/useFactoryAttention.ts:56

    : skipToken;
  return useInfiniteQuery({
    queryKey: [...queryKeys.factoryAttention(factoryProjectId, view, 25), 'history', search],
    queryFn,
    initialPageParam,
    getNextPageParam: lastPage => lastPage.nextCursor,
    staleTime: 2_000,
  });
}

export function useFactoryAttentionReceiptAction(
  factoryProjectId: string | undefined,
  action: FactoryAttentionReceiptAction,
) {
  const { baseUrl } = useApiConfig();
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (item: FactoryAttentionItem) => {
      if (!factoryProjectId) throw new Error('Factory project is required');
      return updateFactoryAttentionReceipt(baseUrl, factoryProjectId, item, action);
    },
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: queryKeys.factoryAttentionRoot(factoryProjectId) });
    },
  });
}

export function useMarkAllFactoryAttentionRead(factoryProjectId: string | undefined) {
  const { baseUrl } = useApiConfig();
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: () => {
      if (!factoryProjectId) throw new Error('Factory project is required');
      return markAllFactoryAttentionRead(baseUrl, factoryProjectId);
    },
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: queryKeys.factoryAttentionRoot(factoryProjectId) });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure `factoryProjectId` is resolved (from route params/query) before rendering the action controls, or disable them until it exists
  2. Pass the project ID explicitly when instantiating the hook
  3. Guard the mutation call site with the same check and surface a user-facing message
  4. If the ID comes from a route, wait for the loader/param before mounting the component

Example fix

// before
const action = useFactoryAttentionReceiptAction(baseUrl, projectId, 'archive');
// after (caller-side guard)
const action = useFactoryAttentionReceiptAction(baseUrl, projectId, 'archive');
<button
  disabled={!projectId || action.isPending}
  onClick={() => projectId && action.mutate(item)}
/>
Defensive patterns

Strategy: validation

Validate before calling

if (!factoryProjectId) {
  // do not mount/enable the mutation or the action buttons
  return <DisabledTooltip message="Select a Factory project first" />;
}

Type guard

function hasProjectId(id: string | null | undefined): id is string {
  return typeof id === 'string' && id.length > 0;
}

Try / catch

try {
  await updateFactoryAttentionReceipt(baseUrl, factoryProjectId, item, action);
} catch (e) {
  if (e instanceof Error && e.message === 'Factory project is required') {
    showToast('Select a Factory project before this action');
  } else throw e;
}

Prevention

When it happens

Trigger: `useFactoryAttentionReceiptAction` is used on a page/component where the `factoryProjectId` param is undefined/null, and the user triggers readItem, archiveItem, or restoreItem.

Common situations: Route param not yet resolved when the component renders (deep-link or refresh before data loads); component used outside a project context; project selection cleared but action buttons still enabled.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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