{"record":{"id":"7e5d30626767bfcb","repo":"mastra-ai/mastra","slug":"github-plugin-url-must-be-in-the-form-https-gith","errorCode":null,"errorMessage":"GitHub plugin URL must be in the form https://github.com/owner/repo","messagePattern":"GitHub plugin URL must be in the form https://github\\.com/owner/repo","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/plugins/install.ts","lineNumber":243,"sourceCode":"function parseGithubUrl(specifier: string): { owner: string; repo: string; repoSpec: string; ref?: string } {\n  const [urlPart, ref] = specifier.split('#', 2);\n  if (!urlPart) {\n    throw new Error(`Invalid GitHub URL: ${specifier}`);\n  }\n  let url: URL;\n  try {\n    url = new URL(urlPart);\n  } catch {\n    throw new Error(`Invalid GitHub URL: ${specifier}`);\n  }\n\n  if (url.hostname !== 'github.com') {\n    throw new Error('Only github.com plugin URLs are supported');\n  }\n\n  const [owner, rawRepo, ...rest] = url.pathname.split('/').filter(Boolean);\n  if (!owner || !rawRepo || rest.length > 0) {\n    throw new Error('GitHub plugin URL must be in the form https://github.com/owner/repo');\n  }\n\n  const repo = rawRepo.replace(/\\.git$/, '');\n  if (!/^[A-Za-z0-9_.-]+$/.test(owner) || !/^[A-Za-z0-9_.-]+$/.test(repo)) {\n    throw new Error('GitHub owner and repo may only contain letters, numbers, dots, underscores, and dashes');\n  }\n\n  return {\n    owner,\n    repo,\n    repoSpec: `${owner}/${repo}`,\n    ...(ref ? { ref } : {}),\n  };\n}\n","sourceCodeStart":225,"sourceCodeEnd":258,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/plugins/install.ts#L225-L258","documentation":"The URL points at github.com but its path does not resolve to exactly owner/repo. parseGithubUrl splits the pathname into non-empty segments and requires exactly two; extra segments (blob paths, subpaths, trees) or missing segments trigger this error.","triggerScenarios":"Passing a repo-browsing URL like 'https://github.com/owner/repo/blob/main/index.ts', a deep link 'https://github.com/owner/repo/tree/v1/src', a bare org URL 'https://github.com/owner', or a URL with trailing junk 'https://github.com/owner/repo/issues'.","commonSituations":"Copying the browser URL while viewing a file or folder in the repo instead of the repo root; linking to issues/releases/PRs instead of the repo.","solutions":["Use the repo root URL: 'https://github.com/owner/repo' (optionally '#ref' for a branch/tag).","Strip path segments after owner/repo — file/tree/blob/issue paths are not valid plugin specifiers.","Ensure both an owner and a repo segment are present; an org-level URL is insufficient."],"exampleFix":"// before\nawait installPlugin('https://github.com/acme/widgets/blob/main/plugin.ts');\n// after\nawait installPlugin('https://github.com/acme/widgets');","handlingStrategy":"validation","validationCode":"function isRepoRootUrl(specifier: string): boolean {\n  try {\n    const segments = new URL(specifier.split('#')[0]).pathname.split('/').filter(Boolean);\n    return segments.length === 2;\n  } catch {\n    return false;\n  }\n}\n// e.g. convert '.../blob/main/plugin.ts' -> '.../owner/repo' before installing","typeGuard":null,"tryCatchPattern":"try {\n  await installPlugin(specifier);\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('GitHub plugin URL must be in the form')) {\n    throw new Error(`Use the repo root URL https://github.com/owner/repo; got \"${specifier}\"`);\n  }\n  throw error;\n}","preventionTips":["Copy URLs from the repo root page, not a file/tree/issues view.","Strip everything after owner/repo in the pathname before installing.","Attach branch/tag via the '#ref' fragment, not extra path segments."],"tags":["plugin-install","url-validation","github"],"backgroundTag":"invalid-url-format","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}