mastra-ai/mastra · error · HTTPException

Stored skill with id ${storedSkillId} not found

Error message

Stored skill with id ${storedSkillId} not found

What it means

When favoriting, the handler loads the stored skill via skillStore.getByIdResolved(storedSkillId). If no skill with that id exists (or has been deleted), it throws HTTPException 404 with a message embedding the requested id. The id is interpolated into the message, so it is safe to log — the resource genuinely does not exist for lookup purposes.

Source

Thrown at packages/server/src/server/handlers/stored-skill-favorites.ts:57

  summary: 'Favorite a stored skill',
  description: 'Marks the stored skill as favorited by the calling user. Idempotent.',
  tags: ['Stored Skills'],
  requiresAuth: true,
  requiresPermission: 'stored-skills:read',
  handler: async ({ mastra, requestContext, storedSkillId }) => {
    try {
      await requireBuilderFeature(mastra, 'favorites');

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

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

      const skill = await skillStore.getByIdResolved(storedSkillId);
      if (!skill) {
        throw new HTTPException(404, { message: `Stored skill with id ${storedSkillId} not found` });
      }
      assertStoredResourceScope(skill, await getStoredResourceScope(mastra, requestContext));

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

      const result = await favoritesStore.favorite({
        userId: callerId,
        entityType: 'skill',
        entityId: storedSkillId,
      });
      return result;
    } catch (error) {
      return handleError(error, 'Error favoriting stored skill');
    }
  },
});

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Verify the storedSkillId exists via GET /stored/skills (list) or the skill's canonical URL and use the correct id
  2. Re-fetch skill ids from the same environment/database the API is pointed at
  3. Handle 404 in the client by refreshing the local list and dropping stale favorites
  4. Check for typos, trailing whitespace, or truncation in the id path parameter

Example fix

// before
await api.put(`/stored/skills/${cachedId}/favorite`);

// after
const skills = await api.get('/stored/skills?authorId=me');
if (!skills.some(s => s.id === cachedId)) cachedId = null; // refresh before favoriting
Defensive patterns

Strategy: validation

Validate before calling

const exists = (await api.get('/stored/skills')).skills.some(s => s.id === storedSkillId);
if (!exists) throw new Error(`Skip favoriting: ${storedSkillId} not found`);

Type guard

function isKnownSkill(skills: { id: string }[], id: string): boolean {
  return skills.some(s => s.id === id);
}

Try / catch

try {
  await api.put(`/stored/skills/${id}/favorite`);
} catch (e) {
  if (isHttpError(e) && e.status === 404) { refreshSkillList(); return; }
  throw e;
}

Prevention

When it happens

Trigger: PUT /stored/skills/:storedSkillId/favorite with an id that was never created, a stale/deleted id, a typo'd id, or an id from a different environment's database.

Common situations: Bookmarks/clients caching skill ids after the skill was deleted; copying ids between dev/staging/prod databases; URL-encoding or whitespace mistakes in the path parameter; hard-coded ids in tests or scripts.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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