mastra-ai/mastra · error · HTTPException

Failed to resolve created skill

Error message

Failed to resolve created skill

What it means

This 500 is thrown when a skill was just created but the immediate `skillStore.getByIdResolved(id)` read-back returns null, meaning the server cannot assemble the resolved skill (thin record + version config) to return. The write succeeded enough not to throw, but the follow-up read found nothing. This indicates an internal consistency/storage anomaly right after create.

Source

Thrown at packages/server/src/server/handlers/stored-skills.ts:372

          visibility,
          name,
          description,
          instructions,
          license,
          compatibility,
          source,
          references: indexedPaths.references ?? references,
          scripts: indexedPaths.scripts ?? scripts,
          assets: indexedPaths.assets ?? assets,
          files,
          metadata: scopeStoredResourceMetadata(metadata, await getStoredResourceScope(mastra, requestContext)),
        },
      });

      // Return the resolved skill (thin record + version config)
      const resolved = await skillStore.getByIdResolved(id);
      if (!resolved) {
        throw new HTTPException(500, { message: 'Failed to resolve created skill' });
      }

      return enrichOrStripFavorites(mastra, requestContext, 'skill', resolved);
    } catch (error) {
      return handleError(error, 'Error creating stored skill');
    }
  },
});

/**
 * PATCH /stored/skills/:storedSkillId - Update a stored skill
 */
export const UPDATE_STORED_SKILL_ROUTE = createRoute({
  method: 'PATCH',
  path: '/stored/skills/:storedSkillId',
  responseType: 'json',
  pathParamSchema: storedSkillIdPathParams,
  bodySchema: updateStoredSkillBodySchema,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Retry the GET /api/stored-skills/:id request — the record may be readable a moment later
  2. Use a storage adapter with strong read-after-write consistency (single primary, no stale replicas)
  3. Check the adapter's `getByIdResolved` implementation for bugs resolving version config
  4. Enable storage logging to confirm the create actually persisted the record and its version rows

Example fix

// before
const skill = await createSkill(...).then(r => r.json());
// after
const res = await createSkill(...);
if (res.status === 500) {
  await new Promise(r => setTimeout(r, 250));
  const skill = await fetch(`/api/stored-skills/${id}`).then(r => r.json());
}
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try {
  const created = await createStoredSkill(body);
  return created;
} catch (e) {
  if (String((e as Error).message).includes('Failed to resolve created skill')) {
    await new Promise(r => setTimeout(r, 250));
    return fetch(`/api/stored-skills/${id}`).then(r => r.json()); // read-back retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Storage adapter with read-after-write inconsistency (e.g. replication lag or caching layer); the create wrote a record that `getByIdResolved` cannot resolve because version config rows were not committed; concurrent delete of the same ID between create and read-back.

Common situations: Custom/experimental storage adapters; distributed Postgres with read replicas serving the immediate read; a bug in a custom `getByIdResolved` implementation; concurrent workers deleting duplicate skills.

Related errors


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