{"record":{"id":"05314f1f26b05b74","repo":"usebruno/bruno","slug":"invalid-git-url","errorCode":null,"errorMessage":"Invalid Git URL","messagePattern":"Invalid Git URL","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/bruno-app/src/utils/git/index.js","lineNumber":29,"sourceCode":"    // Validate that it has the essential parts of a git URL and uses valid protocols\n    const validProtocols = ['git', 'ssh', 'http', 'https'];\n    return !!(\n      parsed\n      && parsed.owner\n      && parsed.source\n      && validProtocols.includes(parsed.protocol)\n    );\n  } catch (error) {\n    return false;\n  }\n};\n\nexport const getRepoNameFromUrl = (url) => {\n  try {\n    const parsedUrl = gitUrlParse(url);\n    return parsedUrl.name;\n  } catch (error) {\n    throw new Error('Invalid Git URL');\n  }\n};\n\nexport const containsGitHubToken = (remoteUrl) => {\n  const GITHUB_TOKEN_REGEX = /(ghp_|gho_|ghu_|ghs_|ghr_)[A-Za-z0-9_]{30,}/;\n  return GITHUB_TOKEN_REGEX.test(remoteUrl);\n};\n\nexport const getSafeGitRemoteUrls = (remotes = []) => {\n  const remoteUrls = remotes\n    ?.map((remote) => remote?.refs?.fetch)\n    ?.filter((url) => typeof url === 'string' && url?.trim()?.length > 0);\n\n  const safeRemoteUrls = remoteUrls\n    ?.filter((remoteUrl) => !containsGitHubToken(remoteUrl));\n  return safeRemoteUrls || [];\n};\n","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/usebruno/bruno/blob/9bdd81c7bdc57006e5f5ebffb79321a8d979f712/packages/bruno-app/src/utils/git/index.js#L11-L47","documentation":"Thrown by getRepoNameFromUrl (git/index.js:29). It delegates to the git-url-parse library to extract the repo name; if the input is empty, undefined, non-string, or otherwise unparseable, the library throws and the catch re-throws a plain 'Invalid Git URL'. Note that a sibling validator isGitRepositoryUrl exists but CloneGitRespository calls getRepoNameFromUrl without first running that check, and its Yup schema only enforces .required().","triggerScenarios":"Passing an empty string, undefined, a bare word with no protocol/owner, or a malformed URL to getRepoNameFromUrl. The clone dialog's Yup validation passes any non-empty string, so a typo like 'myrepo' or 'htp://x' reaches the parser and throws.","commonSituations":"User pastes a partial/typo'd clone URL; URL missing scheme (git@host:owner/repo vs https://...); trailing whitespace or stray characters; form submitted with a non-URL value.","solutions":["Call isGitRepositoryUrl(url) before getRepoNameFromUrl(url) and reject early.","Strengthen the Yup schema with a custom git-URL test (or .url()) so invalid input never reaches the parser.","try/catch getRepoNameFromUrl at the call site (CloneGitRespository/index.js:133) and show a user-facing message.","Trim and normalize the URL (add https:// if no scheme) before parsing."],"exampleFix":"// before\nconst repoName = getRepoNameFromUrl(repositoryUrl);\n\n// after\nimport { isGitRepositoryUrl, getRepoNameFromUrl } from 'utils/git';\nif (!isGitRepositoryUrl(repositoryUrl)) {\n  toast.error('Enter a valid Git URL (https://, git@, ssh://)');\n  return;\n}\nconst repoName = getRepoNameFromUrl(repositoryUrl);","handlingStrategy":"type-guard","validationCode":"import { isGitRepositoryUrl } from 'utils/git';\n\nif (!isGitRepositoryUrl(repositoryUrl)) {\n  toast.error('Enter a valid Git URL (https://, git@, ssh://)');\n  return;\n}","typeGuard":"import { isGitRepositoryUrl } from 'utils/git';\n\nconst isValidGitUrl = (url) =>\n  typeof url === 'string' && url.trim().length > 0 && isGitRepositoryUrl(url);","tryCatchPattern":"try {\n  const repoName = getRepoNameFromUrl(repositoryUrl);\n} catch (e) {\n  toast.error('Enter a valid Git URL (https://, git@, ssh://)');\n  return;\n}","preventionTips":["Always run isGitRepositoryUrl before getRepoNameFromUrl.","Add a Yup .test('git-url', ...) to the clone form, not just .required().","Trim and normalize the URL (add https:// if no scheme) before parsing."],"tags":["git","url-parsing","validation","clone","input"],"backgroundTag":null,"analyzedSha":"9bdd81c7bdc57006e5f5ebffb79321a8d979f712","analyzedAt":"2026-08-13T04:09:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}