different-ai/openwork · error · ApiError
invalid_skill_name
invalid_skill_name
Error message
Skill name must be kebab-case (1-64 chars)
What it means
This 400 invalid_skill_name error is thrown by validateSkillName when a skill name is empty, longer than 64 characters, or fails SKILL_NAME_REGEX (kebab-case pattern). Called from parseSkillEntry, buildSkillContent, and deleteSkill, it guards skill directory naming so names are filesystem- and URL-safe.
Source
Thrown at apps/server/src/validators.ts:11
import { ApiError } from "./errors.js";
const SKILL_NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
const COMMAND_NAME_REGEX = /^[A-Za-z0-9_-]+$/;
const MCP_NAME_REGEX = /^[A-Za-z0-9_-]+$/;
const RESERVED_USER_MCP_NAMES = new Set(["openwork-cloud"]);
const RESERVED_USER_MCP_PREFIXES = ["openwork-connect-"];
export function validateSkillName(name: string): void {
if (!name || name.length < 1 || name.length > 64 || !SKILL_NAME_REGEX.test(name)) {
throw new ApiError(400, "invalid_skill_name", "Skill name must be kebab-case (1-64 chars)");
}
}
export function validateDescription(description: string | undefined): void {
if (!description || description.length < 1 || description.length > 1024) {
throw new ApiError(422, "invalid_description", "Description must be 1-1024 characters");
}
}
export function validatePluginSpec(spec: string): void {
if (!spec || spec.trim().length === 0) {
throw new ApiError(400, "invalid_plugin_spec", "Plugin spec is required");
}
}
export function sanitizeCommandName(name: string): string {
const trimmed = name.trim().replace(/^\/+/, "");
return trimmed;View on GitHub (pinned to 2b7df46e8a)
Solutions
- Convert the name to kebab-case: lowercase, letters/digits/hyphens only, 1-64 chars
- Trim and slugify user-provided titles before calling the API
- Validate the name with the same regex client-side before the request
Example fix
// before const name = title; // "My Cool Skill!" // after const name = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
Defensive patterns
Strategy: validation
Validate before calling
const SLUG = /^[a-z0-9]+(-[a-z0-9]+)*$/;
if (!name || name.length > 64 || !SLUG.test(name)) throw new Error("use kebab-case, 1-64 chars"); Type guard
const isValidSkillName = (name: string): boolean => name.length >= 1 && name.length <= 64 && /^[A-Za-z0-9_-]+$/.test(name);
Try / catch
try {
await createSkill({ name, ...rest });
} catch (e) {
if (e.code === "invalid_skill_name") {
await createSkill({ name: slugify(name), ...rest });
} else throw e;
} Prevention
- Slugify titles: lowercase, replace non-alphanumerics with hyphens, cap at 64 chars
- Validate names with the same regex client-side before any skill API call
- Never pass raw user input or generated titles as skill names
When it happens
Trigger: Creating/updating a skill with a name containing spaces, uppercase-plus-invalid chars per the regex, or >64 chars; e.g. "My Skill!", "a".repeat(65), ""; also deleting with a malformed name.
Common situations: Auto-generated titles used verbatim as skill names; user input not sanitized; names with spaces copied from documentation; marketplace entries with ids that exceed 64 chars.
Related errors
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/de4b404990dc9c83.
Report an issue: GitHub.