Mintplex-Labs/anything-llm · warning
Missing skillName
Error message
Missing skillName
What it means
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.
Source
Thrown at server/endpoints/agentSkillWhitelist.js:56
.json({ available: createFilesTool.isToolAvailable() });
} catch (e) {
console.error(e);
return response
.status(500)
.json({ available: false, error: e.message });
}
}
);
app.post(
"/agent-skills/whitelist/add",
[validatedRequest, flexUserRoleValid(ROLES.all)],
async (request, response) => {
try {
const { skillName } = reqBody(request);
if (!skillName) {
response
.status(400)
.json({ success: false, error: "Missing skillName" });
return;
}
const user = await userFromSession(request, response);
if (!user && response.locals?.multiUserMode) {
return response
.status(401)
.json({ success: false, error: "Unauthorized" });
}
const userId = user?.id || null;
const { success, error } = await AgentSkillWhitelist.add(
skillName,
userId
);
return response.status(success ? 200 : 400).json({ success, error });
} catch (e) {View on GitHub (pinned to 3aec848f28)
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
Example fix
// before
await fetch('/agent-skills/whitelist/add', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({ name: skill }) // wrong key -> 400
});
// after
await fetch('/agent-skills/whitelist/add', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({ skillName: skill })
}); Defensive patterns
Strategy: validation
Validate before calling
function buildWhitelistPayload(skillName) {
if (typeof skillName !== 'string' || skillName.trim().length === 0) {
throw new Error('skillName is required');
}
return { skillName: skillName.trim() };
} Type guard
function isSkillName(v) {
return typeof v === 'string' && v.trim().length > 0;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: Front-end dropdown submitting before a selection; API consumers guessing field names; form-data instead of JSON.
Related errors
- Name and config are required
- Query parameter cannot be empty.
- Message is empty
- Empty entry
- Would exceed ${CHAR_LIMIT} char limit
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/23b3fa6cb726fbe3.
Report an issue: GitHub.