{"record":{"id":"fa22884093efa26b","repo":"github/github-mcp-server","slug":"updated-field-must-be-an-object-fa2288","errorCode":null,"errorMessage":"updated_field must be an object","messagePattern":"updated_field must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/github/projects_batch.go","lineNumber":505,"sourceCode":"\t\treturn 0, err\n\t}\n\tif n <= 0 {\n\t\treturn 0, fmt.Errorf(\"value must be greater than zero (got %d)\", n)\n\t}\n\treturn n, nil\n}\n\ntype batchFieldSpec struct {\n\tid    int64\n\tname  string\n\tvalue any\n}\n\nfunc parseBatchFieldSpec(raw any) (batchFieldSpec, error) {\n\tvar spec batchFieldSpec\n\tinput, ok := raw.(map[string]any)\n\tif !ok || input == nil {\n\t\treturn spec, fmt.Errorf(\"updated_field must be an object\")\n\t}\n\n\tvalue, hasValue := input[\"value\"]\n\tif !hasValue {\n\t\treturn spec, fmt.Errorf(\"updated_field.value is required\")\n\t}\n\tspec.value = value\n\n\tidField, hasID := input[\"id\"]\n\tnameField, hasName := input[\"name\"]\n\tswitch {\n\tcase hasID && hasName:\n\t\treturn spec, fmt.Errorf(\"updated_field must set either id or name, not both\")\n\tcase !hasID && !hasName:\n\t\treturn spec, fmt.Errorf(\"updated_field requires either id or name\")\n\tcase hasID:\n\t\tid, err := validatePositiveInt64(idField)\n\t\tif err != nil {","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/github/projects_batch.go#L487-L523","documentation":"Raised by parseBatchFieldSpec (pkg/github/projects_batch.go:505) when the top-level updated_field argument is not a JSON object — it is a string, number, array, boolean, or null. updated_field is mandatory for update_project_items and must be an object with a value key and exactly one of id or name. This fails the entire request before any item is processed.","triggerScenarios":"\"updated_field\": \"Status\", \"updated_field\": null, \"updated_field\": [\"Status\", \"Done\"], or passing the value directly as \"updated_field\": {\"name\":\"Status\",\"value\":\"Done\"} is correct but \"updated_field\": \"name=Status\" is not. Any non-map JSON value hits the failed type assertion at line 503.","commonSituations":"Misreading the schema and passing just the field name; older/newer tool versions where the argument shape changed; hand-built JSON payloads; MCP clients collapsing a one-property object to a bare string.","solutions":["Wrap the field spec in an object: {\"updated_field\": {\"name\": \"Status\", \"value\": \"Done\"}}","Check the tool's input schema — updated_field is a single object applied to every item in the batch","If you meant different fields per item, that is unsupported: split into one call per field","Validate that updated_field decodes to map[string]any before sending"],"exampleFix":"// before\n{\"updated_field\": \"Status\", ...}\n// after\n{\"updated_field\": {\"name\": \"Status\", \"value\": \"Done\"}, \"items\": [...]}","handlingStrategy":"validation","validationCode":"spec, ok := args[\"updated_field\"].(map[string]any)\nif !ok || spec == nil {\n\treturn fmt.Errorf(\"updated_field must be an object with name/id and value\")\n}","typeGuard":"func isFieldSpecObject(v any) bool { m, ok := v.(map[string]any); return ok && m != nil }","tryCatchPattern":null,"preventionTips":["Pin the tool's argument shape in a typed struct in your client instead of hand-building JSON","Remember updated_field is one object for the whole batch, not per item","Per-item updated_field keys are rejected earlier with a dedicated error — keep the spec top-level"],"tags":["github-projects","batch","input-validation","updated-field"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}