stablyai/orca · warning · Error
Preset directories must be repo-relative paths.
Error message
Preset directories must be repo-relative paths.
What it means
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.
Source
Thrown at src/main/ipc/repos.ts:2783
if (!trimmed) {
throw new Error('Preset name is required.')
}
if (trimmed.length > 80) {
throw new Error('Preset name is too long.')
}
return trimmed
}
function normalizeSparsePresetDirectories(directories: string[]): string[] {
let normalized: string[]
try {
normalized = normalizeSparseDirectories(directories)
} catch (err) {
if (
err instanceof Error &&
err.message === 'Sparse checkout directories must be repo-relative paths.'
) {
throw new Error('Preset directories must be repo-relative paths.')
}
throw err
}
if (normalized.length === 0) {
throw new Error('Preset must have at least one directory.')
}
return normalized
}
View on GitHub (pinned to 1136503c6a)
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.
Example fix
// before
ipc.invoke('sparsePresets:save', { repoId, name, directories })
// after
import { normalizeSparseDirectories } from '@main/ipc/sparse-checkout-directories'
try {
normalizeSparseDirectories(directories) // dry-run on renderer
} catch (e) {
setDirectoryError('Use repo-relative paths, no ".." or drive letters.')
return
}
ipc.invoke('sparsePresets:save', { repoId, name, directories }) Defensive patterns
Strategy: validation
Validate before calling
import { normalizeSparseDirectories } from '@main/ipc/sparse-checkout-directories'
try {
normalizeSparseDirectories(directories) // dry-run
} catch (e) {
setDirectoryError('Use repo-relative paths; no leading slashes, drive letters, or "..".')
return
}
await ipc.invoke('sparsePresets:save', { repoId, name, directories }) Type guard
const DRIVE_RE = /^[A-Za-z]:/
function isRepoRelativeDirectory(entry: string): boolean {
const t = entry.trim()
if (!t || t === '.') return false
if (t.startsWith('/') || t.startsWith('\\') || DRIVE_RE.test(t)) return false
if (t.replace(/\\/g, '/').split('/').includes('..')) return false
return true
} Try / catch
try {
await ipc.invoke('sparsePresets:save', { repoId, name, directories })
} catch (e) {
if (/repo-relative/i.test((e as Error).message)) {
setDirectoryError('One or more paths are not repo-relative.')
} else throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Preset name is required.
- Preset name is too long.
- Preset must have at least one directory.
- Repo "${args.repoId}" not found
- Repo path must be an absolute path
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/a28ccbdb76595927.
Report an issue: GitHub.