{"record":{"id":"37c10964f0741aa1","repo":"mastra-ai/mastra","slug":"pr-failed","errorCode":"pr-failed","errorMessage":"Refusing to open PR: invalid base branch '${base}'.","messagePattern":"Refusing to open PR: invalid base branch '(.+?)'\\.","errorType":"exception","errorClass":"MaterializeError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/github/sandbox.ts","lineNumber":922,"sourceCode":"  return match?.[0];\n}\n\n/**\n * Open a pull request from inside the sandbox via `gh pr create`. The token is\n * passed only through a per-invocation `GH_TOKEN` env scoped to the single `gh`\n * process (never persisted), all arguments are shell-quoted, and the resulting\n * PR URL is parsed from stdout.\n *\n * @param sandbox live sandbox containing the checkout\n * @param workdir the worktree (or repo) path the PR head branch is checked out in\n */\nexport async function createPullRequest(\n  sandbox: ExecutableSandbox,\n  workdir: string,\n  { token, base, head, title, body }: CreatePullRequestArgs,\n): Promise<CreatePullRequestResult> {\n  if (!isValidGitRef(base)) {\n    throw new MaterializeError(`Refusing to open PR: invalid base branch '${base}'.`, 'pr-failed');\n  }\n  if (!isValidGitRef(head)) {\n    throw new MaterializeError(`Refusing to open PR: invalid head branch '${head}'.`, 'pr-failed');\n  }\n\n  await assertGhAvailable(sandbox);\n\n  // GH_TOKEN is prefixed inline so it is exported only to the single `gh`\n  // process and never to the wider shell session, git config, or VM env. `gh`\n  // is run from inside the checkout so it targets the correct repo/head branch.\n  const ghCommand = [\n    `GH_TOKEN=${shellQuote(token)} gh pr create`,\n    `--base ${shellQuote(base)}`,\n    `--head ${shellQuote(head)}`,\n    `--title ${shellQuote(title)}`,\n    `--body ${shellQuote(body ?? '')}`,\n  ].join(' ');\n  const script = `cd ${shellQuote(workdir)} && ${ghCommand}`;","sourceCodeStart":904,"sourceCodeEnd":940,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/github/sandbox.ts#L904-L940","documentation":"createPullRequest validates the base branch with isValidGitRef before invoking `gh pr create`, throwing MaterializeError('pr-failed') on failure. This guards against malformed refspecs and argument injection into the gh command line.","triggerScenarios":"Calling createPullRequest with a base containing spaces, leading dashes, control characters, or an empty string — usually a value derived from untrusted or unparsed input.","commonSituations":"Parsing the base from a diff/PR URL incorrectly; default-branch detection returning an empty value; branch names copied with trailing whitespace.","solutions":["Trim and validate the base branch before calling createPullRequest","Resolve the repo's default branch explicitly (via API) rather than guessing","Reject/sanitize names with whitespace or leading '-'"],"exampleFix":"// before\nawait createPullRequest(sandbox, workdir, { base: ' main', head, title, body });\n// after\nconst base = detectedBase.trim();\nif (!base) throw new Error('base branch is empty');\nawait createPullRequest(sandbox, workdir, { base, head, title, body });","handlingStrategy":"validation","validationCode":"function isValidGitRefLocal(r: string): boolean {\n  return r.length > 0 && !r.startsWith('-') && !/[\\s~^:?*\\[\\\\]/.test(r) && !r.includes('..');\n}\nif (!isValidGitRefLocal(base)) throw new Error(`invalid base branch: ${JSON.stringify(base)}`);","typeGuard":"function isValidBaseBranch(b: string): b is string {\n  return /^[\\w.-]+(\\/[\\w.-]+)*$/.test(b) && !b.startsWith('-');\n}","tryCatchPattern":"try {\n  await createPullRequest(sandbox, workdir, args);\n} catch (e) {\n  if (e instanceof MaterializeError && e.code === 'pr-failed' && e.message.includes('invalid base branch')) {\n    // resolve default branch via API and retry\n  }\n  throw e;\n}","preventionTips":["Resolve the default branch from the GitHub API instead of hardcoding","Trim all branch inputs; reject empty strings early","Use a shared slugify/validator for every branch value"],"tags":["git","validation","pull-request"],"backgroundTag":"invalid-git-branch-name","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}