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
- Pass a full https URL as the specifier, e.g. 'https://github.com/owner/repo' or 'https://github.com/owner/repo#v1.2'.
- Check the variable/config value feeding the specifier is non-empty before calling the install API.
- 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
- Always build specifiers as full https URLs, never bare fragments.
- Assert specifier is non-empty (and trimmed) before any install call.
- Centralize specifier construction in one helper so empty config values fail early.
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
- Only github.com plugin URLs are supported
- GitHub plugin URL must be in the form https://github.com/own
- GitHub owner and repo may only contain letters, numbers, dot
- Invalid GitHub URL format
- Invalid GitHub repository URL. Use https://github.com/<owner
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/dda45a3501a63d50.
Report an issue: GitHub.