stablyai/orca · error

Merge request fetch remote must not start with "-".

Error message

Merge request fetch remote must not start with "-".

What it means

Thrown by fetchGitLabMergeRequestHeadRef when isSafeReviewHeadFetchRemote(remote) is false — the remote name begins with '-', which git would interpret as a flag rather than a refspec argument (argument-injection guard). This protects the downstream `git fetch --no-tags <remote> ...` from a maliciously or accidentally malformed remote name.

Source

Thrown at src/main/gitlab/mr-head-tracking-ref.ts:31

  wslDistro?: string
}

// Why: the relay's read-only git.exec channel rejects `fetch`, so SSH repos
// must use the dedicated git.fetchGitLabMergeRequestHeadRef RPC. Mirrors
// fetchGitHubPullRequestHeadRef so both providers pin the durable head ref
// the same way.
export async function fetchGitLabMergeRequestHeadRef(
  repo: { path: string; connectionId?: string | null },
  sshGitProvider: SshGitProvider | null | undefined,
  remote: string,
  mrIid: number,
  options: { localGitExecOptions?: LocalGitExecOptions } = {}
): Promise<string> {
  if (!isValidReviewHeadNumber(mrIid)) {
    throw new Error(`Invalid merge request iid: ${String(mrIid)}`)
  }
  if (!isSafeReviewHeadFetchRemote(remote)) {
    throw new Error('Merge request fetch remote must not start with "-".')
  }
  if (!repo.connectionId) {
    const localGitExecOptions = options.localGitExecOptions ?? { cwd: repo.path }
    const remoteComponent = await getReviewHeadRemoteComponent(remote, localGitExecOptions)
    // Why: return the same path the fetch wrote so callers don't re-resolve identity.
    const localRef = gitlabMergeRequestHeadLocalRef(remoteComponent, mrIid)
    await gitExecFileAsync(
      ['fetch', '--no-tags', remote, `+refs/merge-requests/${mrIid}/head:${localRef}`],
      {
        ...localGitExecOptions,
        timeout: REVIEW_HEAD_FETCH_TIMEOUT_MS
      }
    )
    return localRef
  }
  if (!sshGitProvider) {
    throw new Error('SSH Git provider is not available. Reconnect to this target and try again.')
  }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Ensure the remote name is one of the actual remotes from `git remote` before calling.
  2. Reject remote names starting with '-' at the input boundary (UI/config parser).
  3. If the remote comes from stored state, validate it against the live `git remote` list on load.

Example fix

// before
await fetchGitLabMergeRequestHeadRef(repo, ssh, userInputRemote, mrIid)
// after
const safeRemote = /^[A-Za-z0-9][\w.-]*$/.test(userInputRemote) ? userInputRemote : null
if (!safeRemote) throw new Error(`Refusing unsafe remote name: ${userInputRemote}`)
await fetchGitLabMergeRequestHeadRef(repo, ssh, safeRemote, mrIid)
Defensive patterns

Strategy: validation

Validate before calling

function isSafeRemoteName(remote: string): boolean {
  return typeof remote === 'string' && remote.length > 0 && !remote.startsWith('-')
}

Type guard

function isSafeReviewHeadFetchRemote(remote: unknown): remote is string {
  return typeof remote === 'string' && remote.length > 0 && !remote.startsWith('-')
}

Prevention

When it happens

Trigger: Passing a remote value that starts with '-' (e.g. '--upload-pack=...', '-o', or any dash-prefixed string) to fetchGitLabMergeRequestHeadRef. Can occur if remote is sourced from untrusted config, a URL query param, or a corrupted stored workspace state.

Common situations: Remote name read from an untrusted/configurable source without sanitization; a bug where an empty remote is replaced by a default flag string; test fixtures passing flag-like strings.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/ba77e04ed14dcd81. Report an issue: GitHub.