GitHub connector update_ref rejects advertised expected_sha argument with InvalidActionArgumentsError
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 75/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- github, rust
- Domain
- backend-api-design
Research direction
Locate the GitHub connector's update_ref action schema in the tool discovery layer and the runtime action binder that processes its arguments. Either implement expected_sha using GitHub's GraphQL updateRefs mutation with beforeOid, or remove it from the advertised schema so both layers agree. Run the connector tests to confirm update_ref no longer rejects the argument unexpectedly.
Written by the indexing model from the issue text.
Description
Summary
The GitHub connector currently advertises an optional expected_sha argument on its update_ref action, apparently intended to provide expected-head / force-with-lease-style protection.
However, calls that include expected_sha are rejected during connector argument processing with:
INVALID_ARGUMENT
InvalidActionArgumentsError
The branch ref is not modified.
Calling the same update_ref action without expected_sha succeeds.
This appears to be a schema/runtime mismatch in the GitHub connector: tool discovery exposes expected_sha, but the deployed action binder does not accept it.
Environment
- Surface: ChatGPT web
- Connector: OpenAI GitHub connector
- Operation:
update_ref - Reproduced: 2026-10-04
- Repository type: normal writable GitHub repository
- Ref update type: branch fast-forward to a newly created Git commit
force:false
The issue was reproduced during a normal Git-data workflow using:
create_blob
→ create_tree
→ create_commit
→ update_ref
Advertised action contract
The connector currently exposes update_ref with arguments equivalent to:
repository_full_name
branch_name
sha
force
expected_sha
expected_sha is described as the expected current branch HEAD, providing lease / expected-head protection.
That makes the following operation appear supported:
update_ref(
branch_name = "feature-branch",
sha = NEW_COMMIT,
force = false,
expected_sha = CURRENT_HEAD
)
Actual behavior
Including expected_sha causes the connector call to fail before the branch ref is updated:
INVALID_ARGUMENT
InvalidActionArgumentsError
After the rejected call, the branch HEAD was explicitly reread and confirmed to be unchanged.
Removing only the expected_sha argument allows the update to succeed:
update_ref(
branch_name = "feature-branch",
sha = NEW_COMMIT,
force = false
)
The branch then advances to the requested commit normally.
Minimal reproduction
Starting state:
branch HEAD = A
Create a new Git commit whose parent is exactly A:
A
└── C
Then call the connector action with:
repository_full_name = <repository>
branch_name = <branch>
sha = C
force = false
expected_sha = A
Observed result
INVALID_ARGUMENT
InvalidActionArgumentsError
Branch remains at:
A
Retry the same operation without expected_sha:
repository_full_name = <repository>
branch_name = <branch>
sha = C
force = false
Observed result
Successful ref movement:
A → C
Expected behavior
One of these should be true:
expected_shais supported as advertised and the connector performs an atomic expected-head update; orexpected_shais not supported and should not appear in the exposed action schema.
The current state is dangerous for tool consumers because the advertised schema implies stronger concurrency semantics than the runtime actually provides.
A caller cannot determine from tool discovery alone that the argument will fail.
Why this does not appear to be a GitHub REST API error
GitHub's REST "Update a reference" endpoint accepts the target SHA and a force flag.
It does not expose an expected_sha request parameter.
Therefore expected_sha appears to be an OpenAI connector abstraction rather than a direct GitHub REST parameter.
The failure also occurs as InvalidActionArgumentsError, and no branch movement occurs, which is consistent with rejection during connector argument binding rather than a rejected GitHub ref update.
Recommended implementation
GitHub's GraphQL API already exposes the exact primitive needed for this behavior.
The updateRefs mutation supports RefUpdate with:
name
beforeOid
afterOid
force
beforeOid requires the ref to point at the specified object before the update is performed.
The connector could therefore implement:
expected_sha → beforeOid
sha → afterOid
branch_name → name
force → force
Conceptually:
updateRefs(
refUpdates: [{
name: "refs/heads/feature-branch"
beforeOid: EXPECTED_SHA
afterOid: NEW_SHA
force: false
}]
)
GitHub performs updateRefs atomically, so this would provide true compare-and-swap / expected-head semantics without a client-side read-check-write race.
Why the current workaround is insufficient as a general solution
For ordinary append-only commits, callers can use:
known HEAD A
→ create commit C with parent A
→ update_ref(C, force=false)
A normal concurrent branch advance will generally cause the update to become non-fast-forward and GitHub will reject it.
That is a useful fallback, but it is not equivalent to true expected-head semantics.
It does not fully cover cases such as:
- force rewrites;
- arbitrary ref movement;
- moving to an already-existing descendant;
- shared branches with unusual concurrent mutation;
- destructive or administrative ref operations.
Those cases need actual compare-and-swap semantics such as beforeOid, or an equivalent force-with-lease implementation.
Additional concern: advertised capability vs runtime capability
This also appears to fit a broader class of connector defects where tool discovery and runtime argument binding are temporarily out of sync.
For agentic workflows, this is particularly costly because an executor may:
- discover the schema;
- design its concurrency strategy around the advertised argument;
- create blobs, trees, and commits;
- reach the final ref mutation;
- discover only then that the advertised argument is rejected.
At minimum, tool discovery and the deployed action implementation should agree on the accepted arguments.
Suggested resolution
Preferred:
- implement
expected_shausing GitHub GraphQLupdateRefs.beforeOid.
Acceptable interim fix:
- remove
expected_shafrom the exposedupdate_refschema until the runtime supports it.
It would also be useful for the action to distinguish an expected-head mismatch from malformed arguments, for example with a dedicated conflict/lease error rather than InvalidActionArgumentsError.
Impact
This affects automated Git workflows that want to perform one logical multi-file mutation as:
create blobs
→ create tree
→ create commit
→ atomically advance branch if HEAD is unchanged
Without working expected-head semantics, callers either have to:
- add redundant branch rereads around ref movement;
- rely only on non-fast-forward protection;
- switch to another Git execution surface for lease-protected mutations.
That increases connector round trips and makes safe high-throughput repository automation harder than necessary.
The existing action schema already appears designed to solve this problem; the runtime simply does not currently honor the advertised argument.
- Dominant language
- Rust
- Stars
- 128k
- Forks
- 20.1k
- Avg merge
- 1m
- Merged PRs (30d)
- 994
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from openai/codex
-
app enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
app bug config windows-os
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
openai/codex#51926 · 2 comments ·
Maintainers usually reply within 1 day
-
app bug model-behavior windows-os
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
openai/codex#51912 · 1 comment ·
Maintainers usually reply within 1 day
-
app bug dots remote
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 1 day
-
app bug performance
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
openai/codex#51818 · 1 comment ·
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
agentic-os-org/ANOLISA#6742 · 1 comment ·
Maintainers usually reply within 1 day
-
api: storage
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
googleapis/google-cloud-rust#7153 ·
Maintainers usually reply within 1 day
-
comp-mysql
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
ClickHouse/ClickHouse#124749 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
oracle/rust-oracledb#43 · 1 comment ·