{"record":{"id":"589cd51fda8ac599","repo":"different-ai/openwork","slug":"command-name-is-required","errorCode":null,"errorMessage":"command.name is required","messagePattern":"command\\.name is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/main.mjs","lineNumber":1524,"sourceCode":"  throw new Error(\"scope must be 'workspace' or 'global'\");\n}\n\nasync function listCommandNames(scope, projectDir) {\n  const commandsDir = resolveCommandsDir(scope, projectDir);\n  if (!(await isDirectory(commandsDir))) {\n    return [];\n  }\n  const entries = await readdir(commandsDir, { withFileTypes: true });\n  return entries\n    .filter((entry) => entry.isFile() && entry.name.endsWith(\".md\"))\n    .map((entry) => entry.name.replace(/\\.md$/, \"\"))\n    .sort();\n}\n\nasync function writeCommandFile(scope, projectDir, command) {\n  const safeName = sanitizeCommandName(command?.name);\n  if (!safeName) {\n    throw new Error(\"command.name is required\");\n  }\n  const commandsDir = resolveCommandsDir(scope, projectDir);\n  await mkdir(commandsDir, { recursive: true });\n  const filePath = path.join(commandsDir, `${safeName}.md`);\n  await writeFile(filePath, serializeCommandFrontmatter({ ...command, name: safeName }), \"utf8\");\n  return execResult(true, `Wrote ${filePath}`);\n}\n\nasync function deleteCommandFile(scope, projectDir, name) {\n  const safeName = sanitizeCommandName(name);\n  if (!safeName) {\n    throw new Error(\"name is required\");\n  }\n  const commandsDir = resolveCommandsDir(scope, projectDir);\n  const filePath = path.join(commandsDir, `${safeName}.md`);\n  if (await pathExists(filePath)) {\n    await rm(filePath, { force: true });\n  }","sourceCodeStart":1506,"sourceCodeEnd":1542,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/desktop/electron/main.mjs#L1506-L1542","documentation":"writeCommandFile sanitizes command?.name via sanitizeCommandName before building the <name>.md path. If the command object is missing, has no name, or its name sanitizes to an empty string (e.g. only illegal characters like '/' or spaces), the write is aborted with 'command.name is required' rather than writing to a bogus path.","triggerScenarios":"Calling the command-write API with command=null/undefined, an object lacking a name field, or a name consisting entirely of characters stripped by sanitizeCommandName (empty string, whitespace-only, slashes/path separators).","commonSituations":"A form in the renderer submitted before the user typed a name, a frontmatter parse dropped the name field, or a name containing only invalid characters ('///') passed validation UI but failed sanitization.","solutions":["Provide a non-empty command name composed of valid characters (alphanumerics, dashes, underscores).","Trim the name and verify it is non-empty after removing invalid characters before saving.","Fix the renderer form to require the name field before enabling Save.","Check that the object being sent is the command itself, not a wrapper ({ command: { name } } vs { name })."],"exampleFix":"// before\nawait writeCommandFile(\"workspace\", dir, { description: \"Run tests\" });\n// after\nawait writeCommandFile(\"workspace\", dir, { name: \"run-tests\", description: \"Run tests\" });","handlingStrategy":"validation","validationCode":"const safe = String(command?.name ?? '').trim();\nif (!safe || /[\\\\/]/.test(safe)) {\n  throw new Error('command.name must be a non-empty filename-safe string');\n}","typeGuard":"function hasCommandName(command) {\n  return typeof command?.name === 'string' && command.name.trim().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Require the name field in the create/edit command form before enabling save.","Mirror sanitizeCommandName rules (no slashes/whitespace-only) in renderer validation.","Send the flat command object with name at top level, matching the handler shape."],"tags":["validation","commands","naming"],"backgroundTag":"missing-required-argument","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}