mastra-ai/mastra · error · Error

Invalid GitHub URL: ${specifier}

Error message

Invalid GitHub URL: ${specifier}

What it means

parseGithubUrl splits the specifier on '#' to separate the URL from an optional git ref. If the part before '#' is empty (or the whole string is empty), it cannot form a URL, so the SDK throws this error. It is the first validation gate when installing a plugin from a GitHub specifier.

Source

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

  try {
    await execa(githubCli, ['--version'], NON_INTERACTIVE_EXEC_OPTIONS);
  } catch {
    throw new Error('GitHub CLI is required to install GitHub plugins. Install gh and run gh auth login.');
  }
}

async function assertGithubCliAuthenticated(githubCli: string): Promise<void> {
  try {
    await execa(githubCli, ['auth', 'status'], NON_INTERACTIVE_EXEC_OPTIONS);
  } catch {
    throw new Error('GitHub CLI is not authenticated. Run gh auth login, then install the plugin again.');
  }
}

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$/, '');

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass a full https URL as the specifier, e.g. 'https://github.com/owner/repo' or 'https://github.com/owner/repo#v1.2'.
  2. Check the variable/config value feeding the specifier is non-empty before calling the install API.
  3. If a ref is desired, keep it after the URL: 'https://github.com/owner/repo#ref', never a bare '#ref'.

Example fix

// before
await installPlugin(process.env.PLUGIN_URL!); // PLUGIN_URL is unset -> ""
// after
const specifier = process.env.PLUGIN_URL;
if (!specifier) throw new Error('PLUGIN_URL is required');
await installPlugin(specifier);
Defensive patterns

Strategy: validation

Validate before calling

function isValidGithubSpecifier(specifier: string): boolean {
  const urlPart = specifier.split('#', 1)[0];
  return typeof urlPart === 'string' && urlPart.trim().length > 0;
}
if (!isValidGithubSpecifier(specifier)) throw new Error('GitHub plugin specifier is empty');

Try / catch

try {
  await installPlugin(specifier);
} catch (error) {
  if (error instanceof Error && error.message.startsWith('Invalid GitHub URL')) {
    console.error(`Specifier "${specifier}" is empty or malformed; use https://github.com/owner/repo[#ref]`);
  }
}

Prevention

When it happens

Trigger: Installing a plugin with an empty or whitespace-only specifier, or a specifier that is just a fragment like '#v1.2' with no URL before the '#'.

Common situations: An unset environment variable or config field interpolated into the specifier (e.g. PLUGIN_URL='' yields '#main'); a shell command that dropped the URL argument; a script building the specifier from a variable that was never populated.

Related errors


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