stablyai/orca · error

Invalid repository name derived from URL

Error message

Invalid repository name derived from URL

What it means

deriveCloneRepoNameFromUrl strips a trailing .git (with optional slash), then takes the POSIX (or win32, for Windows-local sources) basename of the URL. If that basename is empty, '.', or '..', the function throws — these come from URLs whose default clone folder would be the current dir or the parent, which would make a later rm hit the wrong directory. This is the first of two guards (the second at :27 catches a basename that still contains a separator).

Source

Thrown at src/main/git/repo-clone-path.ts:24

  normalizeRuntimePathForComparison,
  normalizeRuntimePathSeparators
} from '../../shared/cross-platform-path'

export type ClaimedCloneTarget = {
  canCleanup: boolean
  ownedDirectoryIdentity: CloneDirectoryIdentity | null
}

type CloneDirectoryIdentity = Pick<Stats, 'dev' | 'ino' | 'birthtimeMs'>

export function deriveCloneRepoNameFromUrl(url: string): string {
  // Why: direct callers can supply URLs whose default git clone folder would
  // be "." or ".."; rejecting them prevents parent/destination deletion.
  const source = url.replace(/\.git\/?$/, '')
  const isWindowsLocalSource = /^[A-Za-z]:[\\/]/.test(source) || source.startsWith('\\\\')
  const repoName = isWindowsLocalSource ? win32.basename(source) : posix.basename(source)
  if (!repoName || repoName === '.' || repoName === '..') {
    throw new Error('Invalid repository name derived from URL')
  }
  if (repoName.includes('/') || repoName.includes('\\')) {
    throw new Error('Invalid repository name derived from URL')
  }
  return repoName
}

export function deriveValidatedClonePath(args: { url: string; destination: string }): string {
  if (
    !args.destination ||
    !isAbsolute(args.destination) ||
    (process.platform !== 'win32' && isWindowsAbsolutePathLike(args.destination))
  ) {
    throw new Error('Clone destination must be an absolute path')
  }

  const repoName = deriveCloneRepoNameFromUrl(args.url)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Validate the URL is non-empty and has a non-root path component before calling deriveCloneRepoNameFromUrl.
  2. If the URL is user input, reject it at the form layer with a clear 'Enter a full repository URL' message.
  3. For file:// URLs, ensure the path points at an actual repo directory, not a drive root.
  4. Prefer deriveValidatedClonePath for end-to-end validation rather than calling deriveCloneRepoNameFromUrl directly.

Example fix

// before
deriveCloneRepoNameFromUrl(userInput) // userInput may be '' or 'file:///'

// after: validate shape first
if (!userInput || !/\/[^/]+(\/)?(\.git)?$/.test(userInput)) {
  throw new Error('Enter a full repository URL with an owner/repo path.')
}
deriveCloneRepoNameFromUrl(userInput)
Defensive patterns

Strategy: validation

Validate before calling

function isValidCloneUrlShape(url: string): boolean {
  if (!url) return false
  const stripped = url.replace(/\.git\/?$/, '')
  const base = /^[A-Za-z]:[\\/]/.test(stripped) || stripped.startsWith('\\\\')
    ? stripped.split(/[\\/]/).pop() ?? ''
    : stripped.split('/').pop() ?? ''
  return Boolean(base) && base !== '.' && base !== '..'
}

if (!isValidCloneUrlShape(url)) throw new Error('Enter a clone URL with a non-empty repository name.')

Type guard

function isInvalidRepoName(error: unknown): boolean {
  return error instanceof Error && error.message === 'Invalid repository name derived from URL'
}

Try / catch

if (!isValidCloneUrlShape(url)) {
  showFormError('clone-url', 'Enter a full repository URL (e.g. https://host/owner/repo).')
  return
}
try {
  deriveCloneRepoNameFromUrl(url)
} catch (error) {
  if (isInvalidRepoName(error)) { showFormError('clone-url', 'That URL has no usable repository name.'); return }
  throw error
}

Prevention

When it happens

Trigger: Calling deriveCloneRepoNameFromUrl(url) or deriveValidatedClonePath({ url, destination }) with a URL like '.', '..', 'file:///', '/', a bare scheme with no path, an empty string, or a URL whose only segment after stripping .git reduces to the POSIX root.

Common situations: A user-typed or pasted clone URL that is incomplete ('https://github.com/'); a file:// URL pointing at a filesystem root; an empty URL from an unvalidated form field; programmatic clone flows where the URL was constructed by joining empty segments; WSL/host path edge cases that reduce to '/' after .git stripping.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/6b7bdb5e68a186a9. Report an issue: GitHub.