{"record":{"id":"989507fa75363754","repo":"stablyai/orca","slug":"preset-must-have-at-least-one-directory","errorCode":null,"errorMessage":"Preset must have at least one directory.","messagePattern":"Preset must have at least one directory\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ipc/repos.ts","lineNumber":2788,"sourceCode":"  }\n  return trimmed\n}\n\nfunction normalizeSparsePresetDirectories(directories: string[]): string[] {\n  let normalized: string[]\n  try {\n    normalized = normalizeSparseDirectories(directories)\n  } catch (err) {\n    if (\n      err instanceof Error &&\n      err.message === 'Sparse checkout directories must be repo-relative paths.'\n    ) {\n      throw new Error('Preset directories must be repo-relative paths.')\n    }\n    throw err\n  }\n  if (normalized.length === 0) {\n    throw new Error('Preset must have at least one directory.')\n  }\n  return normalized\n}\n","sourceCodeStart":2770,"sourceCodeEnd":2792,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/repos.ts#L2770-L2792","documentation":"Thrown by normalizeSparsePresetDirectories when normalizeSparseDirectories returns an empty array. After trimming, stripping leading/trailing slashes, removing '.' and filtering empties/duplicates, at least one directory must remain. Combined with the name checks, this enforces that a preset is non-trivial.","triggerScenarios":"Saving a preset whose only entries were '.', empty strings, whitespace, or duplicates of each other. After normalization nothing survives, so the preset would apply an empty sparse set, which the store refuses.","commonSituations":"Users adding placeholder rows; paste of whitespace-only lines; a UI that allows adding empty directory rows and submitting without filling them.","solutions":["Filter out empty/whitespace entries in the renderer and require >=1 remaining row before enabling Save.","Run normalizeSparseDirectories on the renderer and check the resulting length.","Disable the Save button until at least one non-empty directory is present.","On catch, focus the first empty directory row and prompt the user."],"exampleFix":"// before\nconst directories = rows.map((r) => r.value)\nipc.invoke('sparsePresets:save', { repoId, name, directories })\n\n// after\nconst directories = rows.map((r) => r.value.trim()).filter(Boolean)\nif (directories.length === 0) {\n  setError('Add at least one directory')\n  return\n}\nipc.invoke('sparsePresets:save', { repoId, name, directories })","handlingStrategy":"validation","validationCode":"import { normalizeSparseDirectories } from '@main/ipc/sparse-checkout-directories'\n\nlet normalized: string[]\ntry { normalized = normalizeSparseDirectories(directories) }\ncatch { normalized = [] }\nif (normalized.length === 0) {\n  setError('Add at least one directory.')\n  return\n}\nawait ipc.invoke('sparsePresets:save', { repoId, name, directories })","typeGuard":"function hasAtLeastOneDirectory(dirs: string[]): boolean {\n  return dirs.map((d) => d.trim()).filter((d) => d && d !== '.').length > 0\n}","tryCatchPattern":"try {\n  await ipc.invoke('sparsePresets:save', { repoId, name, directories })\n} catch (e) {\n  if (/at least one directory/i.test((e as Error).message)) setError('Add at least one directory.')\n  else throw e\n}","preventionTips":["Filter empty rows in the renderer and require >=1 remaining.","Disable Save until at least one non-empty directory exists.","Dry-run normalizeSparseDirectories to compute the effective count."],"tags":["ipc","repos","sparse-checkout","preset","validation"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}