{"record":{"id":"be4b5569509b87d3","repo":"mastra-ai/mastra","slug":"failed-to-resolve-skill-after-publish","errorCode":null,"errorMessage":"Failed to resolve skill after publish","messagePattern":"Failed to resolve skill after publish","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"packages/server/src/server/handlers/stored-skills.ts","lineNumber":685,"sourceCode":"        id: storedSkillId,\n        ...snapshotUpdate,\n        tree,\n        files,\n        status: 'published',\n      });\n\n      // Point activeVersionId to the newly created version\n      const latestVersion = await skillStore.getLatestVersion(storedSkillId);\n      if (latestVersion) {\n        await skillStore.update({\n          id: storedSkillId,\n          activeVersionId: latestVersion.id,\n        });\n      }\n\n      const resolved = await skillStore.getByIdResolved(storedSkillId);\n      if (!resolved) {\n        throw new HTTPException(500, { message: 'Failed to resolve skill after publish' });\n      }\n\n      return enrichOrStripFavorites(mastra, requestContext, 'skill', resolved);\n    } catch (error) {\n      return handleError(error, 'Error publishing stored skill');\n    }\n  },\n});\n","sourceCodeStart":667,"sourceCodeEnd":694,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/stored-skills.ts#L667-L694","documentation":"After a successful publish (store.update plus pointing activeVersionId at the new version), the handler re-reads the skill via getByIdResolved to return the fully resolved record. If that read returns null, internal state is inconsistent, so it throws a 500. This is a server-side consistency failure, not a client input problem.","triggerScenarios":"POST to the publish route when getByIdResolved(storedSkillId) returns null immediately after update() succeeded — e.g. the storage adapter fails to join the thin record with its active version, or the row was deleted concurrently.","commonSituations":"Custom or buggy storage adapters whose resolved-read join silently returns null; concurrent deletion of the skill between update and re-read; database replication lag in read-replica setups; schema migrations leaving versions orphaned.","solutions":["Retry the publish request; transient replication/timing issues may self-heal","Verify the stored skill still exists (GET the skill by id) — if it was deleted concurrently, recreate it","Check your storage adapter implementation and version tables for consistency (activeVersionId points at an existing version row)","Report/pin the issue if using a custom storage adapter; test with the default adapter to isolate"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-check that the skill exists and can be read back before publishing\nconst before = await fetch(`${baseUrl}/api/stored/skills/${id}`).then(r => r.json());\nif (!before?.id) throw new Error('Skill not found; publish would be a no-op');","typeGuard":null,"tryCatchPattern":"try {\n  return await publishSkill({ id, skillPath });\n} catch (e) {\n  if (String(e?.message).includes('Failed to resolve skill after publish')) {\n    // transient consistency issue — retry with backoff\n    await new Promise(r => setTimeout(r, 250));\n    return publishSkill({ id, skillPath });\n  }\n  throw e;\n}","preventionTips":["Avoid deleting the skill concurrently with publishing","Keep storage adapter and @mastra/core versions aligned","Prefer maintained adapters (LibSQL/PG) over custom joins for resolved reads","Add an alert/log when publish responses return 500 so consistency bugs surface early"],"tags":["storage","internal-state","http-500","skills"],"backgroundTag":"record-not-found-after-write","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}