abhigyanpatwari/GitNexus · error · InvalidBranchError
: branch name must not start with "+".
Error message
${source}: branch name must not start with "+". What it means
validateBranchName rejects branch names starting with '-' to prevent the name being interpreted as a command-line option when passed to a git subprocess (option-injection defense). A name like '-oProxyCommand=...' would otherwise flow into `git checkout <branch>` style invocations as a flag.
Solutions
- Remove the leading dash from the branch value before calling the API.
- Check argument order in your CLI/script invocation — a missing flag value may have shifted a '-'-prefixed token into the branch slot.
- If the intent was a git option, it is not accepted here; set options via the library's dedicated parameters, never through the branch name.
Example fix
// before const branch = process.argv[4]; // "--force" validateBranchName(branch); // after const branch = process.argv[4]; if (branch) validateBranchName(branch.replace(/^-+/, "")); // "force"
Defensive patterns
Strategy: validation
Validate before calling
function startsWithDash(name) { return typeof name === "string" && name.startsWith("-"); }
if (startsWithDash(branch)) throw new Error("branch name must not start with '-'"); Type guard
function isOptionSafeBranch(v: unknown): v is string {
return typeof v === "string" && !v.trim().startsWith("-");
} Try / catch
try {
validateBranchName(branch, "http");
} catch (e) {
if (e instanceof InvalidBranchError && e.message.includes('start with "-"')) {
return res.status(400).json({ error: "branch names must not start with '-'" });
}
throw e;
} Prevention
- In CLI parsers, use proper flag parsing (e.g. '--branch=value') so '-'-prefixed tokens never land in a value slot.
- For HTTP inputs, reject values starting with '-' before invoking the library.
- Never pass git options through a branch-name parameter; use dedicated options.
- Log and reject suspicious dash-prefixed values — they often indicate injection attempts.
When it happens
Trigger: Calling validateBranchName with a value like '-feature', '--depth=1', or a user/HTTP-supplied branch argument that begins with a dash, e.g. `gitnexus analyze --branch -foo`.
Common situations: Hand-crafted HTTP requests hitting a /branch endpoint with a dash-prefixed value; CLI scripts interpolating flags into a branch variable; typo where a flag value was omitted so the next flag is consumed as the branch name.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- must not start with "-"
- Clone target must be a subdirectory of
- Clone target must resolve inside
- Clone target parent must resolve inside
- Cloning from private/internal addresses is not allowed
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15).
Data as JSON: /api/errors/645ef0b2124832cc.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/git-ref.ts:81
}
assertNoHiddenChars(trimmed, source);
if (/\s/.test(trimmed)) {
throw new InvalidBranchError(`${source}: branch name must not contain whitespace.`);
}
// git ref-name rules (subset): reject characters git itself forbids in refs.
if (/[~^:?*[\\]/.test(trimmed)) {
throw new InvalidBranchError(
`${source}: branch name contains characters not allowed in a git ref (~ ^ : ? * [ \\).`,
);
}
if (trimmed.startsWith('-')) {
throw new InvalidBranchError(`${source}: branch name must not start with "-".`);
}
// Force-refspec prefix (`git fetch origin +main` / `+refs/heads/main:…`).
// Rejected here so neither the CLI nor HTTP can pass a force-update refspec
// through as a "branch" (#3199 review, defense in depth).
if (trimmed.startsWith('+')) {
throw new InvalidBranchError(`${source}: branch name must not start with "+".`);
}
// The symbolic ref HEAD (case-sensitive). A repo can have a branch named
// `head`; git itself treats only `HEAD` as the current-commit alias.
if (trimmed === 'HEAD') {
throw new InvalidBranchError(`${source}: branch name must not be "HEAD".`);
}
if (trimmed.includes('..')) {
throw new InvalidBranchError(`${source}: branch name must not contain "..".`);
}
// The remaining `git check-ref-format` rules. Without these the validator
// accepted refs git itself refuses (`feature.lock`, `/feature`, `feature/`,
// `feature//next`, `@`, `.hidden`), so the failure surfaced later from the
// git subprocess instead of here. No real branch can violate them — git
// could not have created one — so nothing that works today starts failing.
if (trimmed.endsWith('.lock') || trimmed.split('/').some((part) => part.endsWith('.lock'))) {
throw new InvalidBranchError(`${source}: branch name must not end with ".lock".`);
}
if (trimmed.startsWith('/') || trimmed.endsWith('/')) {View on GitHub (pinned to ac9a4e9abd)