{"record":{"id":"8a9f14c852fa297d","repo":"mastra-ai/mastra","slug":"could-not-derive-skill-id-from-name-please-provid","errorCode":null,"errorMessage":"Could not derive skill ID from name. Please provide an explicit id.","messagePattern":"Could not derive skill ID from name\\. Please provide an explicit id\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"packages/server/src/server/handlers/stored-skills.ts","lineNumber":329,"sourceCode":"    visibility: bodyVisibility,\n  }) => {\n    try {\n      const storage = mastra.getStorage();\n\n      if (!storage) {\n        throw new HTTPException(500, { message: 'Storage is not configured' });\n      }\n\n      const skillStore = await storage.getStore('skills');\n      if (!skillStore) {\n        throw new HTTPException(500, { message: 'Skills storage domain is not available' });\n      }\n\n      // Derive ID from name if not explicitly provided\n      const id = providedId || toSlug(name);\n\n      if (!id) {\n        throw new HTTPException(400, {\n          message: 'Could not derive skill ID from name. Please provide an explicit id.',\n        });\n      }\n\n      // Check if skill with this ID already exists\n      const existing = await skillStore.getById(id);\n      if (existing) {\n        throw new HTTPException(409, { message: `Skill with id ${id} already exists` });\n      }\n\n      // Force authorId from the authenticated caller; ignore any body-provided value.\n      // No owner = always public (no auth / no user context).\n      // With an owner, respect the client's choice, defaulting to 'private'.\n      const authorId = getCallerAuthorId(requestContext) ?? undefined;\n      const visibility: 'private' | 'public' = authorId ? (bodyVisibility ?? 'private') : 'public';\n\n      // Derive references/scripts/assets path arrays from the files tree\n      // so agents can discover them via skill_read even when only `files` is provided.","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/stored-skills.ts#L311-L347","documentation":"This 400 is thrown when neither an explicit `id` was provided in the request body nor could `toSlug(name)` produce a non-empty ID, i.e. the handler cannot determine an identifier for the new stored skill. It guards against inserting records with empty/undefined IDs. The library asks the caller to supply the ID explicitly.","triggerScenarios":"POST /api/stored-skills with an empty or missing `name` (e.g. `\"\"` or whitespace-only) and no `id` field; a name made entirely of characters that `toSlug` strips out, yielding an empty string; omitting both fields from the JSON payload.","commonSituations":"Client form allows submitting an empty skill name; programmatic callers send `{}` or a name of only punctuation/emoji that slugifies to nothing; API migration where `id` was previously auto-generated server-side.","solutions":["Provide an explicit `id` in the request body (kebab-case string)","Send a non-empty, meaningful `name` that can be slugified into an ID","Validate name/id client-side before calling the API and reject empty payloads","If generating IDs programmatically, fall back to a UUID/slug when the name is unusable"],"exampleFix":"// before\nawait fetch('/api/stored-skills', { method: 'POST', body: JSON.stringify({ name: '***' }) });\n// after\nawait fetch('/api/stored-skills', { method: 'POST', body: JSON.stringify({ id: 'my-skill', name: 'My Skill' }) });","handlingStrategy":"validation","validationCode":"function assertValidSkillInput(body: { id?: string; name?: string }) {\n  const id = body.id ?? toSlug(body.name ?? '');\n  if (!id) throw new Error('Provide an explicit id or a non-empty slugifiable name');\n  return id;\n}","typeGuard":"function hasDerivableId(b: { id?: string; name?: string }): b is { id: string; name?: string } {\n  return typeof b.id === 'string' && b.id.length > 0;\n}","tryCatchPattern":"try {\n  await createStoredSkill(body);\n} catch (e) {\n  if (String((e as Error).message).includes('derive skill ID')) {\n    // retry with an explicit id\n    await createStoredSkill({ ...body, id: body.id ?? crypto.randomUUID() });\n    return;\n  }\n  throw e;\n}","preventionTips":["Always send an explicit `id` for programmatic creates","Validate `name` is non-empty and contains slugifiable characters client-side","Strip/replace punctuation-only names before submission","Add a form-level required check for name or id"],"tags":["validation","http-400","input","slug"],"backgroundTag":"missing-resource-id","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}