{"record":{"id":"a28ccbdb76595927","repo":"stablyai/orca","slug":"preset-directories-must-be-repo-relative-paths","errorCode":null,"errorMessage":"Preset directories must be repo-relative paths.","messagePattern":"Preset directories must be repo-relative paths\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ipc/repos.ts","lineNumber":2783,"sourceCode":"  if (!trimmed) {\n    throw new Error('Preset name is required.')\n  }\n  if (trimmed.length > 80) {\n    throw new Error('Preset name is too long.')\n  }\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":2765,"sourceCodeEnd":2792,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/repos.ts#L2765-L2792","documentation":"Thrown by normalizeSparsePresetDirectories when normalizeSparseDirectories throws its repo-relative error. This re-wraps the lower-level message ('Sparse checkout directories must be repo-relative paths.') into the preset-specific wording, then re-throws any other error unchanged. It means an entry was absolute (leading slash/backslash or a Windows drive letter) or contained a '..' parent segment.","triggerScenarios":"A user types 'C:\\src' or '/home/user/repo' as a sparse directory; a path with a '..' segment like '../sibling'; a backslash-prefixed Windows path. normalizeSparseDirectories rejects these because they could escape the worktree after slash normalization.","commonSituations":"Users pasting full filesystem paths copied from an explorer; cross-platform input where Windows users type drive letters; templates that bundle absolute paths; path fields that were not validated client-side.","solutions":["Validate each directory with the same isAbsoluteSparseDirectoryPath / '..' rules in the renderer before save.","Strip leading slashes, backslashes, and drive prefixes, and reject '..' segments in the input UI.","Reuse the shared normalizeSparseDirectories on the renderer (it is pure) to preview normalization.","Show inline per-entry validation feedback as the user edits the directory list."],"exampleFix":"// before\nipc.invoke('sparsePresets:save', { repoId, name, directories })\n\n// after\nimport { normalizeSparseDirectories } from '@main/ipc/sparse-checkout-directories'\ntry {\n  normalizeSparseDirectories(directories) // dry-run on renderer\n} catch (e) {\n  setDirectoryError('Use repo-relative paths, no \"..\" or drive letters.')\n  return\n}\nipc.invoke('sparsePresets:save', { repoId, name, directories })","handlingStrategy":"validation","validationCode":"import { normalizeSparseDirectories } from '@main/ipc/sparse-checkout-directories'\n\ntry {\n  normalizeSparseDirectories(directories) // dry-run\n} catch (e) {\n  setDirectoryError('Use repo-relative paths; no leading slashes, drive letters, or \"..\".')\n  return\n}\nawait ipc.invoke('sparsePresets:save', { repoId, name, directories })","typeGuard":"const DRIVE_RE = /^[A-Za-z]:/\nfunction isRepoRelativeDirectory(entry: string): boolean {\n  const t = entry.trim()\n  if (!t || t === '.') return false\n  if (t.startsWith('/') || t.startsWith('\\\\') || DRIVE_RE.test(t)) return false\n  if (t.replace(/\\\\/g, '/').split('/').includes('..')) return false\n  return true\n}","tryCatchPattern":"try {\n  await ipc.invoke('sparsePresets:save', { repoId, name, directories })\n} catch (e) {\n  if (/repo-relative/i.test((e as Error).message)) {\n    setDirectoryError('One or more paths are not repo-relative.')\n  } else throw e\n}","preventionTips":["Validate each directory with the same rules in the renderer.","Run normalizeSparseDirectories as a dry-run before the IPC.","Show per-entry feedback as the user edits the list."],"tags":["ipc","repos","sparse-checkout","preset","validation","path-safety"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}