mastra-ai/mastra · error · Error

GitHub plugin URL must be in the form https://github.com/own

Error message

GitHub plugin URL must be in the form https://github.com/owner/repo

What it means

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.

Source

Thrown at mastracode/sdk/src/plugins/install.ts:243

function parseGithubUrl(specifier: string): { owner: string; repo: string; repoSpec: string; ref?: string } {
  const [urlPart, ref] = specifier.split('#', 2);
  if (!urlPart) {
    throw new Error(`Invalid GitHub URL: ${specifier}`);
  }
  let url: URL;
  try {
    url = new URL(urlPart);
  } catch {
    throw new Error(`Invalid GitHub URL: ${specifier}`);
  }

  if (url.hostname !== 'github.com') {
    throw new Error('Only github.com plugin URLs are supported');
  }

  const [owner, rawRepo, ...rest] = url.pathname.split('/').filter(Boolean);
  if (!owner || !rawRepo || rest.length > 0) {
    throw new Error('GitHub plugin URL must be in the form https://github.com/owner/repo');
  }

  const repo = rawRepo.replace(/\.git$/, '');
  if (!/^[A-Za-z0-9_.-]+$/.test(owner) || !/^[A-Za-z0-9_.-]+$/.test(repo)) {
    throw new Error('GitHub owner and repo may only contain letters, numbers, dots, underscores, and dashes');
  }

  return {
    owner,
    repo,
    repoSpec: `${owner}/${repo}`,
    ...(ref ? { ref } : {}),
  };
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use the repo root URL: 'https://github.com/owner/repo' (optionally '#ref' for a branch/tag).
  2. Strip path segments after owner/repo — file/tree/blob/issue paths are not valid plugin specifiers.
  3. Ensure both an owner and a repo segment are present; an org-level URL is insufficient.

Example fix

// before
await installPlugin('https://github.com/acme/widgets/blob/main/plugin.ts');
// after
await installPlugin('https://github.com/acme/widgets');
Defensive patterns

Strategy: validation

Validate before calling

function isRepoRootUrl(specifier: string): boolean {
  try {
    const segments = new URL(specifier.split('#')[0]).pathname.split('/').filter(Boolean);
    return segments.length === 2;
  } catch {
    return false;
  }
}
// e.g. convert '.../blob/main/plugin.ts' -> '.../owner/repo' before installing

Try / catch

try {
  await installPlugin(specifier);
} catch (error) {
  if (error instanceof Error && error.message.startsWith('GitHub plugin URL must be in the form')) {
    throw new Error(`Use the repo root URL https://github.com/owner/repo; got "${specifier}"`);
  }
  throw error;
}

Prevention

When it happens

Trigger: 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'.

Common situations: 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.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/7e5d30626767bfcb. Report an issue: GitHub.