abhigyanpatwari/GitNexus · error · Error

must use an SSH URL on github.com, gitlab.com, or gitee.com

Error message

must use an SSH URL on github.com, gitlab.com, or gitee.com

What it means

GitNexus auto-sync only accepts SSH-style remote URLs of the form git@host:owner/repo.git. This error is thrown by validateAutoSyncRemoteUrl when the configured remote_url does not match the required SSH regex at all — it is not HTTPS, not scp-like SSH syntax, or contains whitespace. The library throws it early (config parse / clone) to guarantee the downstream git clone command is unambiguous and safe.

Source

Thrown at gitnexus/src/core/auto-sync/config.ts:290

  return {
    configPath,
    syncIntervalMinutes: interval,
    repoGitTimeoutMs,
    analyzeTimeoutMs,
    maxConcurrency,
    analyzeFailureThreshold,
    projects,
  };
}

export function validateAutoSyncRemoteUrl(remoteUrl: string): void {
  const trimmed = remoteUrl.trim();
  if (trimmed.includes('?') || trimmed.includes('#')) {
    throw new Error('must not include query strings or fragments');
  }
  const match = /^git@([^:\s/]+):([^\s]+)$/.exec(trimmed);
  if (!match) {
    throw new Error('must use an SSH URL on github.com, gitlab.com, or gitee.com');
  }
  const host = match[1].toLowerCase();
  const repoPath = match[2];
  if (!ALLOWED_REMOTE_HOSTS.has(host)) {
    throw new Error('host must be one of github.com, gitlab.com, or gitee.com');
  }
  const pathParts = repoPath.split('/');
  // Every segment becomes a directory component: the namespace segments build
  // the clone path and the last one names the repo. So each is held to the same
  // charset, which is what keeps a separator out of a segment — on Windows
  // `..\..\outside` is traversal even though the segment is not literally `..`,
  // and testing the raw string for `..` instead would reject an ordinary
  // `foo..bar`. Traversal is a whole segment; a separator is a character.
  const namespaceParts = pathParts.slice(0, -1);
  if (
    repoPath.startsWith('/') ||
    pathParts.length < 2 ||
    pathParts.some((part) => !part || part === '.' || part === '..') ||

View on GitHub (pinned to 0d1aed942f)

Solutions

  1. Replace the remote URL with scp-like SSH syntax: git@github.com:owner/repo.git (colon, not slash, after host; no scheme).
  2. Remove any scheme prefix (https://, ssh://) and any port segment — only git@host:path is accepted.
  3. Confirm the host is github.com, gitlab.com, or gitee.com — a different host will pass this check but fail the next one with 'host must be one of...'.
  4. Run git remote -v or `git ls-remote <url>` locally to confirm the URL works over SSH before putting it in the auto-sync config.

Example fix

// before
remote_url = https://github.com/acme/widgets.git
// after
remote_url = git@github.com:acme/widgets.git
Defensive patterns

Strategy: validation

Validate before calling

function isValidSshRemoteUrl(url) {
  const t = (url ?? '').trim();
  if (t.includes('?') || t.includes('#')) return false;
  return /^git@(github\.com|gitlab\.com|gitee\.com):[\w.-]+[\/][\w.\/-]+\.git$/.test(t);
}
// run before passing remote_url into the config
if (!isValidSshRemoteUrl(cfg.remote_url)) throw new Error(`bad remote_url: ${cfg.remote_url}`);

Type guard

function isSshRemote(u) {
  return typeof u === 'string' && /^git@[^:\s/]+:\S+$/.test(u.trim());
}

Try / catch

try {
  const cfg = parseAutoSyncConfig(raw);
} catch (e) {
  if (String(e.message).includes('must use an SSH URL')) {
    log.error(`remote_url '${cfg?.remote_url}' must be git@host:owner/repo.git`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling parseAutoSyncConfig with a remote_url like https://github.com/owner/repo.git, or a git:// / ssh:// prefixed URL, or an SSH URL with a port (ssh://git@github.com:22/owner/repo.git), or a URL with spaces. Also thrown by extractRepoNameFromRemoteUrl, getAutoSyncRepoIdentity, and cloneOrPull when handed the same malformed value.

Common situations: Developer copies the HTTPS clone URL from the GitHub/GitLab 'Code' button instead of the SSH one; config written before SSH keys were set up; organization moved to self-hosted GitLab with a different hostname; URL pasted with a trailing newline or embedded spaces.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@0d1aed942f (2026-09-08). Data as JSON: /api/errors/814d8360c74069d7. Report an issue: GitHub.