bmad-code-org/BMAD-METHOD · error · Error
Unsafe ref name: ${JSON.stringify(ref)}
Error message
Unsafe ref name: ${JSON.stringify(ref)} What it means
Thrown by quoteCustomRef() when a Git ref (branch/tag name) fails the whitelist regex ^[\w.\-+/]+$. The function exists to safely embed user-supplied or URL-parsed refs into git --branch and git fetch commands, preventing shell injection. Any ref containing spaces, semicolons, pipes, or other shell metacharacters is rejected before reaching execSync.
Source
Thrown at tools/installer/modules/custom-module-manager.js:10
const fs = require('../fs-native');
const os = require('node:os');
const path = require('node:path');
const { execSync } = require('node:child_process');
const prompts = require('../prompts');
const { gitEnv } = require('./git-env');
function quoteCustomRef(ref) {
if (typeof ref !== 'string' || !/^[\w.\-+/]+$/.test(ref)) {
throw new Error(`Unsafe ref name: ${JSON.stringify(ref)}`);
}
return `"${ref}"`;
}
function isLocalSourcePath(input) {
return (
input.startsWith('/') ||
input.startsWith('./') ||
input.startsWith('../') ||
input.startsWith('.\\') ||
input.startsWith('..\\') ||
input.startsWith('~') ||
path.win32.isAbsolute(input)
);
}
/**
* Manages custom modules installed from user-provided sources.View on GitHub (pinned to b70486b9bd)
Solutions
- Check the ref string for whitespace or shell metacharacters and remove/escape them before passing as a version suffix.
- If the ref is a raw commit SHA, note that git clone --branch cannot use SHAs — use --pin at the module level or a branch/tag name instead.
- Ensure options.pinOverride, when provided, is a simple alphanumeric/semver tag string.
- URL-encode branch names containing slashes inside the path, or quote the @version suffix properly.
Example fix
// before const url = 'https://github.com/org/repo.git@feature/fix bug'; await mgr.cloneRepo(url); // after const url = 'https://github.com/org/repo.git@feature/fix-bug'; await mgr.cloneRepo(url);
Defensive patterns
Strategy: validation
Validate before calling
function isValidRef(ref) {
return typeof ref === 'string' && /^[\w.\-+/]+$/.test(ref);
}
// Before calling cloneRepo:
const version = extractVersion(url);
if (version && !isValidRef(version)) {
throw new Error(`Invalid ref name: ${version}`);
} Type guard
function isSafeRef(ref) {
return typeof ref === 'string' && ref.length > 0 && /^[\w.\-+/]+$/.test(ref) && !ref.includes('//');
} Try / catch
try {
await mgr.cloneRepo(url, { pinOverride });
} catch (e) {
if (e.message.startsWith('Unsafe ref name')) {
console.error('The version/tag contains invalid characters. Use only letters, digits, dots, hyphens, underscores, plus, and slashes.');
}
throw e;
} Prevention
- Validate all user-supplied refs against ^[\w.\-+/]+$ before passing to the installer.
- Never pass raw commit SHAs as version suffixes — git clone --branch does not support them.
- Sanitize --pin values at the CLI boundary before they reach internal APIs.
- Test branch/tag names with 'git check-ref-format' if unsure.
When it happens
Trigger: Calling CustomModuleManager.cloneRepo() with a source URL whose @version suffix or /tree/<ref> path segment contains characters outside [A-Za-z0-9_.\-+/]. Also triggered when a parsed default branch name from git symbolic-ref contains unexpected characters, or when options.pinOverride is set to a malformed value.
Common situations: A user supplies a URL like https://github.com/org/repo.git@feature/my branch (space in branch name); a ref with a colon like 'HEAD~1'; a non-string pinOverride passed programmatically; a ref derived from a malformed deep-path URL that the parser partially consumed.
Related errors
- Unsafe ref name: ${JSON.stringify(ref)}
- Not a valid Git URL or local path
- Source is required
- Local paths do not support @version suffixes
- Path does not exist: ${resolved}
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/6d533efdfd4dfcd0.
Report an issue: GitHub.