github/github-mcp-server · error
each item must set exactly one of node_id, item_id, or item_
Error message
each item must set exactly one of node_id, item_id, or item_owner + item_repo + issue_number, not more than one
What it means
Raised by parseItemRef (pkg/github/projects_batch.go:409) when an items[] entry sets more than one of the accepted reference forms (node_id, item_id, or the issue triple). The library refuses to guess which identifier wins, so the item is rejected as 'invalid_item_ref' and excluded from writes.
Source
Thrown at pkg/github/projects_batch.go:409
_, hasIssueNumber := entry["issue_number"]
hasIssueRef := hasOwner || hasRepo || hasIssueNumber
formsPresent := 0
if hasNodeID {
formsPresent++
}
if hasItemID {
formsPresent++
}
if hasIssueRef {
formsPresent++
}
switch {
case formsPresent == 0:
return fmt.Errorf("each item requires exactly one of node_id, item_id, or item_owner + item_repo + issue_number")
case formsPresent > 1:
return fmt.Errorf("each item must set exactly one of node_id, item_id, or item_owner + item_repo + issue_number, not more than one")
}
switch {
case hasNodeID:
s, ok := entry["node_id"].(string)
if !ok || s == "" {
return fmt.Errorf("node_id must be a non-empty string")
}
p.refKind = batchRefNodeID
p.nodeID = s
case hasItemID:
id, err := validatePositiveInt64(entry["item_id"])
if err != nil {
return fmt.Errorf("item_id: %w", err)
}
p.refKind = batchRefItemID
p.itemID = id
default:View on GitHub (pinned to 0ea1f775a7)
Solutions
- Keep exactly one form per item and delete the other reference keys
- Prefer node_id — it is used directly without a lookup; item_id and issue refs each cost an extra resolution call
- If the data source yields multiple identifiers, pick one deterministically (node_id first) before building the request
- Pre-validate: count the forms per item and reject any item whose count is not exactly 1
Example fix
// before
{"items": [{"node_id": "PVTI_x", "item_id": 12345}]}
// after
{"items": [{"node_id": "PVTI_x"}]} Defensive patterns
Strategy: validation
Validate before calling
func refFormCount(entry map[string]any) int {
n := 0
if _, ok := entry["node_id"]; ok { n++ }
if _, ok := entry["item_id"]; ok { n++ }
issue := false
for _, k := range []string{"item_owner", "item_repo", "issue_number"} {
if _, ok := entry[k]; ok { issue = true }
}
if issue { n++ }
return n
}
// require refFormCount(item) == 1 for every item before sending Type guard
func hasExactlyOneRefForm(entry map[string]any) bool { return refFormCount(entry) == 1 } Prevention
- Pick one canonical reference form per pipeline (prefer node_id) and strip the others at build time
- Remember any one of item_owner/item_repo/issue_number counts as the whole issue-ref form
- Reject items that carry more than one form before the call — the tool refuses to disambiguate
When it happens
Trigger: An item like {"node_id":"PVTI_x","item_id":123} (two forms), or {"node_id":"PVTI_x","item_owner":"octo","item_repo":"repo","issue_number":7} — note any one of item_owner/item_repo/issue_number present makes hasIssueRef true, so node_id plus just item_repo already counts as two forms.
Common situations: A 'send every identifier we have' client that stuffs all known IDs into each item; merging payloads from two sources where one used node_id and the other item_id; template defaults that pre-populate item_owner while code adds node_id.
Related errors
- updated_field must set either id or name, not both
- each item requires exactly one of node_id, item_id, or item_
- node_id must be a non-empty string
- item_id: %w
- item_owner, item_repo, and issue_number must all be provided
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/df06866d19622faa.
Report an issue: GitHub.