abhigyanpatwari/GitNexus · error · Error

Invalid URL

Error message

Invalid URL

What it means

validateGitUrl's first step parses the input with new URL(); any string the WHATWG URL parser rejects — missing scheme, embedded spaces/control characters, bare 'github.com/user/repo' — throws and is rethrown as 'Invalid URL'. This is the malformed-input gate in front of the SSRF checks that follow.

Solutions

  1. Trim whitespace/newlines from the URL before submitting
  2. Prepend https:// when the scheme is missing
  3. Run new URL(url) client-side as a pre-flight check
  4. Convert scp-style git@host:repo remotes to https://host/repo form

Example fix

// before
const url = 'github.com/user/repo.git';
validateGitUrl(url); // Invalid URL

// after
const url = 'https://github.com/user/repo.git';
validateGitUrl(url); // ok
Defensive patterns

Strategy: validation

Validate before calling

function isParseableHttpUrl(s) {
  if (typeof s !== 'string') return false;
  try { const u = new URL(s.trim()); return u.protocol === 'https:' || u.protocol === 'http:'; }
  catch { return false; }
}

Type guard

function asTrimmedAbsoluteUrl(raw) {
  const s = typeof raw === 'string' ? raw.trim() : '';
  if (!s) return null;
  const withScheme = /^[a-z][a-z0-9+.-]*:/i.test(s) ? s : `https://${s}`;
  try { return new URL(withScheme).href; } catch { return null; }
}

Try / catch

try { validateGitUrl(url); }
catch (e) {
  if (e.message === 'Invalid URL') { const fixed = asTrimmedAbsoluteUrl(url); if (!fixed) throw e; validateGitUrl(fixed); }
  else throw e;
}

Prevention

When it happens

Trigger: POST /api/analyze with url lacking a scheme ('github.com/user/repo.git'), containing raw spaces or newlines ('https:// ex ample.com'), or otherwise unparseable garbage such as pasted placeholder text.

Common situations: Users omitting https:// because git itself tolerates it; copy-paste introducing whitespace or a newline; frontends not trimming the field; scp-style 'git@host:repo' syntax, which the URL parser cannot parse at all.

Related errors


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

Appendix: source

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

}

/**
 * Derive a clone directory name for the web `/api/analyze` boundary.
 *
 * The API historically accepted Azure DevOps and similar URLs whose repo
 * segment contains spaces or other directory-unsafe characters by sanitizing
 * the final segment. Keep that compatibility at the web boundary while leaving
 * `extractRepoName()` strict for internal/security-sensitive callers.
 */
export function extractWebRepoName(url: string): string {
  let trimmed = url.trim();
  while (trimmed.endsWith('/')) trimmed = trimmed.slice(0, -1);
  const withoutGit = trimmed.toLowerCase().endsWith('.git') ? trimmed.slice(0, -4) : trimmed;
  const rawName = withoutGit.split(/[/:]/).filter(Boolean).pop() ?? '';
  const safeName = sanitizeRepoName(rawName);
  if (!rawName || safeName === 'unknown') {
    throw new Error('Could not extract a valid repository name from URL');
  }
  return safeName;
}

/**
 * Longest single path component the supported filesystems accept (ext4, APFS,
 * NTFS all cap at 255). Compared against `.length`, which equals the byte
 * count here because every name this guards is ASCII by construction
 * (REPO_NAME_PATTERN and sanitizeRepoName both restrict to `[a-zA-Z0-9._-]`).
 */
const MAX_PATH_COMPONENT_BYTES = 255;

/**
 * `branchSlug` for a clone-directory name, trimmed to fit one path component.
 *
 * `validateBranchName` allows a ref up to 255 characters and `branchSlug`
 * appends `-` plus 8 hash characters, so `<repo>__<slug>` can reach 267 — past
 * the filesystem limit, and the clone would then fail to create its target
 * directory (#3199 review).

View on GitHub (pinned to ac9a4e9abd)