github/github-mcp-server · error

each item requires exactly one of node_id, item_id, or item_

Error message

each item requires exactly one of node_id, item_id, or item_owner + item_repo + issue_number

What it means

Raised by parseItemRef (pkg/github/projects_batch.go:407) when an entry in items[] contains none of the accepted item reference forms. Each item must carry exactly one of: node_id, item_id, or the triple item_owner + item_repo + issue_number. The offending item is marked code 'invalid_item_ref' and excluded from the batch; valid sibling items still execute.

Source

Thrown at pkg/github/projects_batch.go:407

	_, hasOwner := entry["item_owner"]
	_, hasRepo := entry["item_repo"]
	_, 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

View on GitHub (pinned to 0ea1f775a7)

Solutions

  1. Add exactly one reference form to each failing item — node_id (string), item_id (positive integer), or item_owner + item_repo + issue_number together
  2. Check the exact snake_case key names in items[i]; the error names them literally
  3. Pre-validate the items array before calling the tool so one bad item does not waste a batch round-trip
  4. Prefer node_id when you have it: it skips the extra lookup the other two forms require

Example fix

// before
{"items": [{"note": "no reference"}], "updated_field": {"name": "Status", "value": "Done"}}
// after
{"items": [{"node_id": "PVTI_lADOABC123"}], "updated_field": {"name": "Status", "value": "Done"}}
Defensive patterns

Strategy: validation

Validate before calling

// Go: validate each item before calling update_project_items
func validRefKeys(it map[string]any) bool {
	n := 0
	for _, k := range []string{"node_id", "item_id"} {
		if _, ok := it[k]; ok { n++ }
	}
	if _, ok := it["item_owner"]; ok { n++ }
	if _, ok := it["item_repo"]; ok { n++ }
	if _, ok := it["issue_number"]; ok { n++ }
	return n > 0
}
for _, it := range items {
	if m, ok := it.(map[string]any); !ok || !validRefKeys(m) { return fmt.Errorf("item missing item reference: %v", it) }
}

Type guard

func hasAnyRefForm(entry map[string]any) bool {
	for _, k := range []string{"node_id", "item_id", "item_owner", "item_repo", "issue_number"} {
		if _, present := entry[k]; present {
			return true
		}
	}
	return false
}

Prevention

When it happens

Trigger: Passing items like {}, {"title":"Fix login"}, or an object whose reference keys are misspelled (camelCase nodeId/itemId, bare owner/repo/number, REST-style "id") so that node_id, item_id, item_owner, item_repo, and issue_number are all absent.

Common situations: Generating the items array from a CSV/template where reference columns are optional and blank; schema drift between an internal model (camelCase IDs) and the tool's snake_case arguments; copy-pasting a REST payload that uses "id" for the node ID.

Related errors


AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15). Data as JSON: /api/errors/8c9d101c5a878795. Report an issue: GitHub.