{"record":{"id":"22fad9c489612795","repo":"sinelaw/fresh","slug":"folder-name-must-not-be-empty","errorCode":null,"errorMessage":"folder name must not be empty","messagePattern":"folder name must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/plugins/orchestrator.ts","lineNumber":10642,"sourceCode":"  // Depth-first from the top level, so parents precede their children and\n  // siblings come out in the order `childFoldersOf` gives the dock.\n  const walk = (parent: string | null, depth: number): void => {\n    for (const f of childFoldersOf(parent)) {\n      out.push({ folderId: f.id, name: f.name, parent: f.parent ?? null, depth });\n      walk(f.id, depth + 1);\n    }\n  };\n  walk(null, 0);\n  return out;\n}\n\nfunction apiCreateFolder(name: string, parent?: string | null): string {\n  const clean = trimmed(name);\n  // The dialog falls back to \"New Folder\" on an empty submit because a human\n  // who typed nothing meant \"just make me one\". A caller passing an empty\n  // string meant something else — most likely a variable that didn't hold\n  // what they thought — so it is an error rather than a silent default.\n  if (!clean) throw new Error(\"folder name must not be empty\");\n  const parentId = parent ?? null;\n  if (parentId !== null && !folderById(parentId)) {\n    throw new Error(`no such folder: ${parentId}`);\n  }\n  const id = createFolder(clean, parentId);\n  refreshDockTree();\n  return id;\n}\n\nfunction apiRenameFolder(folderId: string, name: string): boolean {\n  if (!folderById(folderId)) return false;\n  const clean = trimmed(name);\n  if (!clean) throw new Error(\"folder name must not be empty\");\n  renameFolder(folderId, clean);\n  refreshOpenDialog();\n  return true;\n}\n","sourceCodeStart":10624,"sourceCodeEnd":10660,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/plugins/orchestrator.ts#L10624-L10660","documentation":"apiCreateFolder validates that the folder name, after trimming whitespace, is non-empty and throws otherwise. The interactive dialog defaults an empty submit to \"New Folder\", but a programmatic caller passing \"\" almost certainly has a bug (e.g. an unset variable), so the library errors instead of silently applying the dialog's default. The parent id is validated next (see the 'no such folder' error for parents).","triggerScenarios":"Calling apiCreateFolder(\"\"), apiCreateFolder(\"   \"), or with a name variable that is undefined/empty at the call site.","commonSituations":"Config or env var that failed to load, leaving the intended folder name empty; template interpolation that produced an empty string; off-by-one parsing that dropped the actual name.","solutions":["Provide a non-empty, non-whitespace name to apiCreateFolder","Check the variable or config value feeding the name for emptiness before calling","If you truly want a default, pass a concrete name like \"New Folder\" explicitly"],"exampleFix":"// before\napi.createFolder(nameFromConfig);\n// after\nconst clean = (nameFromConfig ?? \"\").trim();\nif (!clean) throw new Error(\"folder name must not be empty\");\napi.createFolder(clean);","handlingStrategy":"validation","validationCode":"const clean = (name ?? \"\").trim();\nif (!clean) throw new Error(\"refusing to create folder with empty name\");","typeGuard":"function isValidFolderName(name) {\n  return typeof name === \"string\" && name.trim().length > 0;\n}","tryCatchPattern":"try {\n  api.createFolder(name);\n} catch (e) {\n  if (String(e).includes(\"must not be empty\")) {\n    api.createFolder(\"New Folder\");\n  } else throw e;\n}","preventionTips":["Trim and check every folder name before calling","Validate the config/env variable feeding the name loads correctly","Never rely on the dialog's \"New Folder\" default from scripts — pass an explicit name","Log the raw value when a name variable is suspicious (undefined vs empty)"],"tags":["typescript","validation","empty-value"],"backgroundTag":"empty-required-field","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}