mastra-ai/mastra · error · HTTPException

Authentication required

Error message

Authentication required

What it means

The favorites toggle handler derives the caller's author id from requestContext via getCallerAuthorId. When the request carries no authenticated caller identity, the handler throws HTTPException 401 'Authentication required'. Favoriting is a per-user action, so an anonymous caller cannot be served.

Source

Thrown at packages/server/src/server/handlers/stored-agent-favorites.ts:50

 */
export const FAVORITE_STORED_AGENT_ROUTE = createRoute({
  method: 'PUT',
  path: '/stored/agents/:storedAgentId/favorite',
  responseType: 'json',
  pathParamSchema: storedAgentIdPathParams,
  responseSchema: favoriteToggleResponseSchema,
  summary: 'Favorite a stored agent',
  description: 'Marks the stored agent as favorited by the calling user. Idempotent.',
  tags: ['Stored Agents'],
  requiresAuth: true,
  requiresPermission: 'stored-agents:read',
  handler: async ({ mastra, requestContext, storedAgentId }) => {
    try {
      await requireBuilderFeature(mastra, 'favorites');

      const callerId = getCallerAuthorId(requestContext);
      if (!callerId) {
        throw new HTTPException(401, { message: 'Authentication required' });
      }

      const { agentStore, favoritesStore } = await getFavoritesContext(mastra);

      const agent = await agentStore.getById(storedAgentId);
      if (!agent) {
        throw new HTTPException(404, { message: `Stored agent with id ${storedAgentId} not found` });
      }
      assertStoredResourceScope(agent, await getStoredResourceScope(mastra, requestContext));

      // Throws 404 if the caller cannot read the agent (private + not owner/admin).
      assertReadAccess({ requestContext, resource: 'stored-agents', resourceId: storedAgentId, record: agent });

      const result = await favoritesStore.favorite({
        userId: callerId,
        entityType: 'agent',
        entityId: storedAgentId,
      });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Attach valid credentials (Authorization header or session cookie) to the request
  2. Refresh or re-obtain the auth token if expired
  3. Confirm auth middleware is registered and runs before the favorites route
  4. Verify getCallerAuthorId's expected requestContext key is populated by your auth provider

Example fix

// before
fetch('/api/stored-agents/123/favorite', { method: 'PUT' })
// after
fetch('/api/stored-agents/123/favorite', {
  method: 'PUT',
  headers: { Authorization: `Bearer ${token}` },
  credentials: 'include',
})
Defensive patterns

Strategy: try-catch

Validate before calling

// Before calling the API
const token = getSessionToken();
if (!token) redirectToLogin();

Type guard

function hasCallerIdentity(ctx: unknown): ctx is { callerAuthorId: string } {
  return typeof ctx === 'object' && ctx !== null && typeof (ctx as any).callerAuthorId === 'string' && (ctx as any).callerAuthorId.length > 0;
}

Try / catch

try {
  await api.toggleFavorite(agentId);
} catch (e) {
  if (e.status === 401) { refreshToken(); redirectToLogin(); }
  else throw e;
}

Prevention

When it happens

Trigger: PUT /stored/agents/:storedAgentId/favorite (and other favorites routes) without an authenticated user in requestContext — missing/invalid auth token, expired session, or auth middleware not populating the caller identity.

Common situations: Calling the API from a script without attaching credentials; expired JWT/session cookie; auth middleware misconfigured or bypassed on the playground/server proxy; builder feature enabled but auth not wired up.

Understand the failure class

Related errors


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