Windows PowerShell parses git @{u} upstream shorthand as a hashtable literal

Open 💬 2 comments Opened Jun 28, 2026 by Efs-O

Bug: git rev-parse ... @{u} fails on Windows because PowerShell parses @{u} as a hashtable literal

Summary

On Windows with PowerShell as the shell, Codex's tool router runs

git rev-parse --abbrev-ref --symbolic-full-name @{u}

by handing it to PowerShell as a command string. PowerShell sees @{ and tries
to parse @{u} as a hashtable literal, which fails before git is ever
invoked:

At line:2 char:52
+ git rev-parse --abbrev-ref --symbolic-full-name @{u}
+                                                    ~
Missing '=' operator after key in hash literal.
The hash literal was incomplete.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEqualsInHashLiteral

The command exits 1 and the upstream-branch lookup never runs. In git, @{u}
(a.k.a. @{upstream}) is the revision shorthand for "the upstream of the current
branch" - a perfectly valid git argument that PowerShell mangles because @{...}
is hashtable syntax in PowerShell.

Environment

  • OS: Windows 10 Pro (10.0.19045)
  • Shell: Windows PowerShell 5.1 (5.1.19041.7417) - also reproduces on

PowerShell 7, since @{ is hashtable syntax in all PowerShell editions

  • Codex CLI: 0.142.2
  • ChatGPT VS Code extension: 26.623.42026 (win32-x64)

Actual log line (from the Codex output channel)

[error] [CodexMcpConnection] cli: message="... ERROR codex_core::tools::router:
error=Exit code: 1
Wall time: 0.4 seconds
Output:
At line:2 char:52
+ git rev-parse --abbrev-ref --symbolic-full-name @{u}
+                                                    ~
Missing '=' operator after key in hash literal.
At line:2 char:52
+ git rev-parse --abbrev-ref --symbolic-full-name @{u}
+                                                    ~
The hash literal was incomplete.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEqualsInHashLiteral"

Steps to reproduce

  1. On Windows, with PowerShell as the active shell, open a git repository whose

current branch has an upstream configured.

  1. Use Codex in a flow that triggers its branch/upstream detection (it runs

git rev-parse --abbrev-ref --symbolic-full-name @{u} internally; observed via
turn-diff / branch-status capture).

  1. Open the Codex output channel and observe the ParserError above.

Minimal standalone repro of the underlying cause (no Codex needed):

# FAILS - PowerShell parses @{u} as a hashtable literal:
git rev-parse --abbrev-ref --symbolic-full-name @{u}

# WORKS - quoting stops PowerShell from parsing the braces:
git rev-parse --abbrev-ref --symbolic-full-name '@{u}'

# WORKS - stop-parsing token passes the rest verbatim:
git --% rev-parse --abbrev-ref --symbolic-full-name @{u}

Expected behavior

git rev-parse --abbrev-ref --symbolic-full-name @{u} should run and return the
upstream branch (e.g. origin/main), regardless of which shell Codex uses on
Windows.

Root cause

Codex builds the git invocation as a PowerShell command string, so the
@{u} argument is subject to PowerShell's parser. @{ ... } is PowerShell's
hashtable-literal syntax; @{u} has a key with no =, so PowerShell raises a
ParserError (MissingEqualsInHashLiteral) and never spawns git. This is a
shell-quoting / argument-passing issue specific to the Windows PowerShell path -
on bash/zsh the same string is passed through to git unharmed.

Suggested fixes (any one resolves it)

  1. Pass argv directly, bypassing shell parsing. Spawn git with an argument

array (e.g. Start-Process/CreateProcess-style argv, or git.exe invoked
with discrete args) instead of composing one PowerShell command string. This
is the most robust fix and avoids an entire class of PowerShell-quoting bugs.

  1. Quote the revision argument when targeting PowerShell:

... --symbolic-full-name '@{u}'.

  1. Use the PowerShell stop-parsing token --% before the git args so the

remainder is passed verbatim: git --% rev-parse ... @{u}.

Option 1 is preferred because other git revision/argument forms (HEAD@{0},
@{push}, paths/globs with special chars) can hit similar PowerShell-parsing
pitfalls.

Impact / severity

Low severity, but persistent and Windows-specific:

  • Affects only the Windows + PowerShell path; macOS/Linux are unaffected

(which is likely why it has survived frequent extension updates - the
PowerShell path is under-tested).

  • It fails a non-critical background helper (upstream-branch / turn-diff

capture), so the user's primary command still works; the failure surfaces only
as a log error, generating little user-facing signal.

  • Net effect: noisy, repeated ParserError in the Codex output channel on every

affected turn, and broken upstream-branch detection for Windows PowerShell
users.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗