{"record":{"id":"23b3fa6cb726fbe3","repo":"Mintplex-Labs/anything-llm","slug":"missing-skillname","errorCode":null,"errorMessage":"Missing skillName","messagePattern":"Missing skillName","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"server/endpoints/agentSkillWhitelist.js","lineNumber":56,"sourceCode":"          .json({ available: createFilesTool.isToolAvailable() });\n      } catch (e) {\n        console.error(e);\n        return response\n          .status(500)\n          .json({ available: false, error: e.message });\n      }\n    }\n  );\n\n  app.post(\n    \"/agent-skills/whitelist/add\",\n    [validatedRequest, flexUserRoleValid(ROLES.all)],\n    async (request, response) => {\n      try {\n        const { skillName } = reqBody(request);\n        if (!skillName) {\n          response\n            .status(400)\n            .json({ success: false, error: \"Missing skillName\" });\n          return;\n        }\n\n        const user = await userFromSession(request, response);\n        if (!user && response.locals?.multiUserMode) {\n          return response\n            .status(401)\n            .json({ success: false, error: \"Unauthorized\" });\n        }\n\n        const userId = user?.id || null;\n        const { success, error } = await AgentSkillWhitelist.add(\n          skillName,\n          userId\n        );\n        return response.status(success ? 200 : 400).json({ success, error });\n      } catch (e) {","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/endpoints/agentSkillWhitelist.js#L38-L74","documentation":"POST /agent-skills/whitelist/add returns this 400 when reqBody(request) yields no truthy `skillName`. The endpoint is available to all roles in multi-user mode; skillName is the only required field and there is no format constraint beyond being present.","triggerScenarios":"POST with body {} or {skillName:''} or {skillName:null}; request without JSON content-type so the body is unparsed; sending the field under a different key (name, skill).","commonSituations":"Front-end dropdown submitting before a selection; API consumers guessing field names; form-data instead of JSON.","solutions":["Send {\"skillName\":\"<exact skill name>\"} as JSON with Content-Type: application/json","Use the skill identifier exactly as listed by the agent-skills discovery endpoint/UI (no renaming or casing changes)","Client-side, disable the add button until a non-empty skillName is selected"],"exampleFix":"// before\nawait fetch('/agent-skills/whitelist/add', {\n  method:'POST',\n  headers:{'Content-Type':'application/json'},\n  body: JSON.stringify({ name: skill }) // wrong key -> 400\n});\n\n// after\nawait fetch('/agent-skills/whitelist/add', {\n  method:'POST',\n  headers:{'Content-Type':'application/json'},\n  body: JSON.stringify({ skillName: skill })\n});","handlingStrategy":"validation","validationCode":"function buildWhitelistPayload(skillName) {\n  if (typeof skillName !== 'string' || skillName.trim().length === 0) {\n    throw new Error('skillName is required');\n  }\n  return { skillName: skillName.trim() };\n}","typeGuard":"function isSkillName(v) {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Send the field as `skillName` exactly — no aliases","Populate the value from the server's skill list, never free-typed input","Disable submit until a skill is selected"],"tags":["agent-skills","whitelist","http-400","request-body"],"backgroundTag":"request-body-validation","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}