{"record":{"id":"9aeb0d15c392e0d4","repo":"paperclipai/paperclip","slug":"github-source-must-be-a-github-or-github-enterpris","errorCode":null,"errorMessage":"GitHub source must be a GitHub or GitHub Enterprise URL, or owner/repo[/path] shorthand.","messagePattern":"GitHub source must be a GitHub or GitHub Enterprise URL, or owner/repo\\[/path\\] shorthand\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/client/company.ts","lineNumber":904,"sourceCode":"  return url.toString();\n}\n\nexport function normalizeGithubImportSource(input: string, refOverride?: string): string {\n  const trimmed = input.trim();\n  const ref = refOverride?.trim();\n\n  if (isGithubShorthand(trimmed)) {\n    const [owner, repo, ...repoPath] = trimmed.split(\"/\").filter(Boolean);\n    return buildGithubImportUrl({\n      owner: owner!,\n      repo: repo!,\n      ref: ref || \"main\",\n      path: repoPath.join(\"/\"),\n    });\n  }\n\n  if (!looksLikeRepoUrl(trimmed)) {\n    throw new Error(\"GitHub source must be a GitHub or GitHub Enterprise URL, or owner/repo[/path] shorthand.\");\n  }\n  if (!ref) {\n    return trimmed;\n  }\n\n  const url = new URL(trimmed);\n  const hostname = url.hostname;\n  const parts = url.pathname.split(\"/\").filter(Boolean);\n  if (parts.length < 2) {\n    throw new Error(\"Invalid GitHub URL.\");\n  }\n\n  const owner = parts[0]!;\n  const repo = parts[1]!;\n  const existingPath = normalizeGithubImportPath(url.searchParams.get(\"path\"));\n  const existingCompanyPath = normalizeGithubImportPath(url.searchParams.get(\"companyPath\"));\n  if (existingCompanyPath) {\n    return buildGithubImportUrl({ hostname, owner, repo, ref, companyPath: existingCompanyPath });","sourceCodeStart":886,"sourceCodeEnd":922,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/client/company.ts#L886-L922","documentation":"Thrown by normalizeGithubImportSource when the input is neither GitHub shorthand (owner/repo[/path]) nor a valid https URL with at least two path segments. The function only accepts full https GitHub/GHE URLs or the owner/repo shorthand; anything else (bare hostnames, non-https URLs, file paths) is rejected.","triggerScenarios":"Passing 'git@github.com:owner/repo.git' (SSH form), 'github.com/owner/repo' (no scheme), 'http://...' (non-https), a local filesystem path, or a one-segment URL like 'https://github.com/owner'. looksLikeRepoUrl returns false for all of these.","commonSituations":"Copying the SSH clone URL from GitHub's green button instead of the HTTPS web URL. Pasting a bare 'owner/repo' with a trailing slash that breaks segment checks. Using a GHE URL on http instead of https.","solutions":["Use the HTTPS web URL: 'https://github.com/owner/repo' or 'https://github.example.com/owner/repo'.","Use shorthand: 'owner/repo' or 'owner/repo/sub/path'.","For GHE, make sure the scheme is https; if your GHE is http-only, file a feature request — the current guard rejects it.","Avoid the SSH form 'git@host:owner/repo.git'; convert it to https://host/owner/repo first."],"exampleFix":"# before\npaperclipai company import --source git@github.com:acme/widget.git\n# after\npaperclipai company import --source https://github.com/acme/widget\n# or shorthand\npaperclipai company import --source acme/widget","handlingStrategy":"validation","validationCode":"function validateGithubSource(source: string): void {\n  const trimmed = source.trim();\n  const ok = /^https:\\/\\//i.test(trimmed) || /^[A-Za-z0-9._-]+\\/[A-Za-z0-9._-]+/.test(trimmed);\n  if (!ok) {\n    throw new Error(\"Provide an https GitHub URL or owner/repo shorthand.\");\n  }\n}","typeGuard":"function isAcceptableGithubSource(input: string): boolean {\n  const t = input.trim();\n  if (!t) return false;\n  if (/^https:\\/\\//i.test(t)) {\n    try {\n      const u = new URL(t);\n      return u.pathname.split(\"/\").filter(Boolean).length >= 2;\n    } catch {\n      return false;\n    }\n  }\n  return /^[A-Za-z0-9._-]+\\/[A-Za-z0-9._-]+/.test(t);\n}","tryCatchPattern":null,"preventionTips":["Always copy the HTTPS URL from the browser address bar, not the SSH clone button.","Validate the source string before handing it to the CLI in scripts.","Prefer the owner/repo shorthand for brevity and to avoid scheme mistakes."],"tags":["cli","validation","github","url-parsing","company-import"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}