abhigyanpatwari/GitNexus · error · Error

Could not extract a valid repository name from URL

Error message

Could not extract a valid repository name from URL

What it means

extractRepoName takes the last path segment of a git URL (via parseRepoNameFromUrl) and requires a filesystem-safe name matching ^[a-zA-Z0-9._-]+$, additionally rejecting '.', '..', and the 'unknown' sentinel. Anything else throws, because getCloneDir would otherwise let names like '..' or 'foo/bar' escape the clone root via path traversal.

Source

Thrown at gitnexus/src/server/git-clone.ts:50

export const REPO_NAME_PATTERN = /^[a-zA-Z0-9._-]+$/;

/**
 * Extract the repository name from a git URL (HTTPS or SSH).
 *
 * Throws if the URL does not yield a filesystem-safe last segment. A name
 * like `..` or `foo/bar` would otherwise let `getCloneDir(name)` escape the
 * clone root via path traversal.
 */
export function extractRepoName(url: string): string {
  const name = parseRepoNameFromUrl(url);
  if (
    !name ||
    name === '.' ||
    name === '..' ||
    name === 'unknown' ||
    !REPO_NAME_PATTERN.test(name)
  ) {
    throw new Error('Could not extract a valid repository name from URL');
  }
  return name;
}

/** Get the clone target directory for a repo name. */
export function getCloneDir(repoName: string): string {
  // Re-validate at the boundary even though extractRepoName already checked —
  // callers may pass a repoName from another source (test fixtures, scripts).
  if (!repoName || repoName === '.' || repoName === '..' || !REPO_NAME_PATTERN.test(repoName)) {
    throw new Error('Invalid repository name');
  }
  return path.join(CLONE_ROOT, repoName);
}

// Cloud metadata hostnames that must never be reachable via user-supplied URLs
const BLOCKED_HOSTNAMES = new Set([
  'localhost',
  'metadata.google.internal',

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Send the canonical HTTPS URL ending in the repo slug, optionally with .git
  2. Ensure the repo slug is pure ASCII alphanumerics plus . _ - (rename or alias non-ASCII slugs)
  3. Trim whitespace and strip fragments/queries from user-pasted URLs before submitting

Example fix

// before
const url = 'https://github.com/user/my repo';
extractRepoName(url); // throws

// after
const url = 'https://github.com/user/my-repo';
extractRepoName(url); // 'my-repo'
Defensive patterns

Strategy: validation

Validate before calling

const SAFE_NAME = /^[a-zA-Z0-9._-]+$/;
function lastSegment(url) { return new URL(url).pathname.replace(/\/+$/, '').split('/').pop() || ''; }
function urlYieldsSafeRepoName(url) {
  try { const n = lastSegment(url).replace(/\.git$/, ''); return SAFE_NAME.test(n) && n !== '.' && n !== '..' && n !== 'unknown'; }
  catch { return false; }
}

Type guard

function isSafeRepoName(name) {
  return typeof name === 'string' && name.length > 0 && name !== '.' && name !== '..' && name !== 'unknown' && /^[a-zA-Z0-9._-]+$/.test(name);
}

Try / catch

try { targetPath = getCloneDir(extractRepoName(url)); }
catch (e) {
  if (e.message === 'Could not extract a valid repository name from URL') throw new BadRequest(`unsupported repo url: ${url}`, 400);
  throw e;
}

Prevention

When it happens

Trigger: POST /api/analyze (or any cloneOrPull caller) with a URL whose final segment is empty ('https://github.com/user/') or contains characters outside the safe set — spaces ('my repo'), CJK/unicode, backslashes, or shell metacharacters ('repo;ls').

Common situations: Trailing-slash or bare-host URLs; repositories with human-display names containing spaces/unicode; pasted URLs with a trailing fragment or whitespace; URLs where the repo slug itself is non-ASCII.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/520285eb83c45f4c. Report an issue: GitHub.