{"record":{"id":"80c276f4ce7dad27","repo":"yarnpkg/yarn","slug":"invalid-hosted-git-fragment-0","errorCode":null,"errorMessage":"Invalid hosted git fragment $0.","messagePattern":"Invalid hosted git fragment \\$0\\.","errorType":"validation","errorClass":"MessageError","httpStatus":null,"severity":"error","filePath":"src/resolvers/exotics/hosted-git-resolver.js","lineNumber":42,"sourceCode":"export function explodeHostedGitFragment(fragment: string, reporter: Reporter): ExplodedFragment {\n  const hash = parseHash(fragment);\n\n  const preParts = fragment.split('@');\n  if (preParts.length > 2) {\n    fragment = preParts[1] + '@' + preParts[2];\n  }\n\n  const parts = fragment\n    .replace(/(.*?)#.*/, '$1') // Strip hash\n    .replace(/.*:(.*)/, '$1') // Strip prefixed protocols\n    .replace(/.git$/, '') // Strip the .git suffix\n    .split('/');\n\n  const user = parts[parts.length - 2];\n  const repo = parts[parts.length - 1];\n\n  if (user === undefined || repo === undefined) {\n    throw new MessageError(reporter.lang('invalidHostedGitFragment', fragment));\n  }\n\n  return {\n    user,\n    repo,\n    hash,\n  };\n}\n\nexport default class HostedGitResolver extends ExoticResolver {\n  constructor(request: PackageRequest, fragment: string) {\n    super(request, fragment);\n\n    const exploded = (this.exploded = explodeHostedGitFragment(fragment, this.reporter));\n    const {user, repo, hash} = exploded;\n    this.user = user;\n    this.repo = repo;\n    this.hash = hash;","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/yarnpkg/yarn/blob/c2dda503f3759b5be5f0e24ecd9cf5c97a540147/src/resolvers/exotics/hosted-git-resolver.js#L24-L60","documentation":"explodeHostedGitFragment() strips protocol/hash/.git then splits by '/'; if user or repo ends up undefined (the fragment cannot split into a user/repo pair), it throws. Used for github:/bitbucket:/gitlab: style dependencies.","triggerScenarios":"A hosted-git dependency string that, after normalization, lacks a user or repo segment (parts[parts.length-2] or parts[parts.length-1] is undefined).","commonSituations":"Malformed github: URLs missing a segment; trailing slashes confusing the split; pasting only a repo without user.","solutions":["Use the format github:<user>/<repo> or github:<user>/<repo>#<commit>","Check the dependency URL has both a user and repo segment","Remove trailing slashes or extra path segments beyond user/repo"],"exampleFix":"// before\n\"my-dep\": \"github:user\"\n// after\n\"my-dep\": \"github:user/repo\"","handlingStrategy":"validation","validationCode":"function isValidHostedGitFragment(fragment: string): boolean {\n  const cleaned = fragment.replace(/(.*?)#.*/, '$1').replace(/.*:(.*)/, '$1').replace(/.git$/, '');\n  const parts = cleaned.split('/');\n  return parts[parts.length - 2] !== undefined && parts[parts.length - 1] !== undefined;\n}","typeGuard":"function isWellFormedHostedGit(fragment: string): boolean {\n  const parts = fragment.replace(/(.*?)#.*/, '$1').replace(/.*:(.*)/, '$1').replace(/.git$/, '').split('/');\n  const user = parts[parts.length - 2];\n  const repo = parts[parts.length - 1];\n  return !!user && !!repo;\n}","tryCatchPattern":null,"preventionTips":["Use github:<user>/<repo>[#<commit>] format consistently","Avoid trailing slashes and extra path segments in hosted-git URLs","Validate the fragment has both user and repo before committing"],"tags":["hosted-git","exotic-resolver","fragment"],"backgroundTag":null,"analyzedSha":"c2dda503f3759b5be5f0e24ecd9cf5c97a540147","analyzedAt":"2026-08-13T04:17:06.305Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}