Skip to content

fix(kanban-router): use -f over -F for ID/String GraphQL vars - #25

Merged
LukasWodka merged 1 commit into
mainfrom
fix/kanban-router-status-opt-string-coercion
Apr 29, 2026
Merged

fix(kanban-router): use -f over -F for ID/String GraphQL vars#25
LukasWodka merged 1 commit into
mainfrom
fix/kanban-router-status-opt-string-coercion

Conversation

@aptracebloc

@aptraceblocaptracebloc commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Summary

The kanban closure router fails on every PR merge with gh: Variable $o of type String! was provided invalid value. Two of the six Status option IDs on project #2 are all-digit strings, so gh api -F was coercing them to JSON numbers — which the GraphQL schema rejects.

First failing run: tracebloc-py-package#108 → run 25111214624.

What happened

PR tracebloc-py-package#108 was merged → router workflow correctly decided status=Done → then died on the GraphQL mutation with:

gh: Variable $o of type String! was provided invalid value

Root cause

The router shells out with:

gh api graphql -f query='...mutation...' \
-F p="$PROJECT_ID" -F i="$ITEM_ID" -F f="$STATUS_FIELD" -F o="$STATUS_OPT"

The gh api flag conventions matter:

  • -F = typed: digit-only strings get coerced to numbers
  • -f = always string

The Status option IDs on project #2 are:

StatusOption ID
Backlogf75ad846
Ready61e4505c
In progress47fc9ee4
In reviewdf73e18b
Validation90729828 ← all digits
Done98236657 ← all digits

-F o="98236657" makes gh send the value as a JSON number 98236657, but the GraphQL schema declares $o: String!. Server rejects it. Hence the failure.

The other three vars (PROJECT_ID, ITEM_ID, STATUS_FIELD) all start with prefixes like PVT_…, PVTI_…, PVTSSF_… — alphanumeric, so -F happens to behave correctly. STATUS_OPT is the only one that can be all-digit, and right now 2 of the 6 statuses (Done and Validation) trigger it. Done is the one the router writes most often, so this would have hit on every merged PR.

Fix

Change the four -F flags on the mutation call to -f. The GraphQL types involved are ID! / String! — never numeric — so -f is correct for all four and removes the latent risk for the other three IDs too.

 gh api graphql -f query='
mutation($p: ID!, $i: ID!, $f: ID!, $o: String!) {
updateProjectV2ItemFieldValue(input: {
projectId: $p, itemId: $i, fieldId: $f,
value: {singleSelectOptionId: $o}
}) { projectV2Item { id } }
- }' -F p="$PROJECT_ID" -F i="$ITEM_ID" -F f="$STATUS_FIELD" -F o="$STATUS_OPT"+ }' -f p="$PROJECT_ID" -f i="$ITEM_ID" -f f="$STATUS_FIELD" -f o="$STATUS_OPT"

After the fix, retry by closing/merging any test PR; the log should show → #N → Status=Done instead of the GraphQL error.

Why "Cancelled" status didn't blow up too

If/when a Cancelled Status option gets added, check whether its ID is also all-digit — same bug would hit closed-but-unmerged PRs going forward. The -f fix covers that too.

Side note

PR tracebloc-py-package#108 was the rollout PR adding this caller workflow into that repo — so this was the very first real-world execution of the new routing system. First run, first bug.

Test plan

  • Merge a test PR in any repo that uses the caller workflow, confirm the kanban item moves to Done and the workflow run is green.
  • Close (without merging) a test PR, confirm the item moves to Cancelled (once that Status option exists / when applicable).
  • Confirm previously-failing run 25111214624 can be re-run successfully (or no longer matters once the next merge passes).

Note

Low Risk
Single-line change in a GitHub Actions workflow; it only affects how GraphQL variables are serialized for a status-update mutation.

Overview
Fixes the reusable kanban-closure-router GitHub Actions workflow by passing GraphQL variables to gh api graphql with -f (string) instead of -F (typed) when updating the ProjectV2 Status field, preventing all-digit option IDs from being coerced to numbers and rejected by the GraphQL String! schema.

Reviewed by Cursor Bugbot for commit 10a9de0. Bugbot is set up for automated code reviews on this repo. Configure here.

`gh api -F` performs type inference: digit-only strings are sent as
JSON numbers. Two Status option IDs on project #2 are all-digit
(`Done`=98236657, `Validation`=90729828), which made the
`updateProjectV2ItemFieldValue` mutation reject them with
`Variable $o of type String! was provided invalid value`.
Switch the four `-F` flags on the mutation call to `-f` so they're
always serialized as strings. The GraphQL types involved are
`ID!`/`String!`, never numeric, so `-f` is correct for all four.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@aptraceblocaptracebloc self-assigned this Apr 29, 2026

@LukasWodkaLukasWodka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — clean root-cause analysis in the body, fix is correct (-f always-string is right for all four ID!/String! vars). All checks green. Merging now since every PR-merge → kanban Done flow is currently failing on this.

@LukasWodka
LukasWodka merged commit 2e70195 into mainApr 29, 2026
3 checks passed
@LukasWodkaLukasWodka added bug Something isn't working work-type:bug Defect or regression labels Jun 8, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't workingwork-type:bugDefect or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aptracebloc@LukasWodka