{"record":{"id":"47634ee67f6db98e","repo":"github/github-mcp-server","slug":"commentnodeid-cannot-be-blank","errorCode":null,"errorMessage":"commentNodeID cannot be blank","messagePattern":"commentNodeID cannot be blank","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/github/discussions.go","lineNumber":755,"sourceCode":"\tcomment := mutation.AddDiscussionComment.Comment\n\tout, err := json.Marshal(MinimalResponse{\n\t\tID:  fmt.Sprintf(\"%v\", comment.ID),\n\t\tURL: string(comment.URL),\n\t})\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to marshal comment: %w\", err)\n\t}\n\n\treturn utils.NewToolResultText(string(out)), nil, nil\n}\n\nfunc requiredCommentNodeID(args map[string]any) (string, error) {\n\tcommentNodeID, err := RequiredParam[string](args, \"commentNodeID\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif strings.TrimSpace(commentNodeID) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"commentNodeID cannot be blank\")\n\t}\n\treturn commentNodeID, nil\n}\n\nfunc replyToDiscussionComment(ctx context.Context, client *githubv4.Client, args map[string]any) (*mcp.CallToolResult, any, error) {\n\tcommentNodeID, err := requiredCommentNodeID(args)\n\tif err != nil {\n\t\treturn utils.NewToolResultError(err.Error()), nil, nil\n\t}\n\n\towner, err := RequiredParam[string](args, \"owner\")\n\tif err != nil {\n\t\treturn utils.NewToolResultError(err.Error()), nil, nil\n\t}\n\trepo, err := RequiredParam[string](args, \"repo\")\n\tif err != nil {\n\t\treturn utils.NewToolResultError(err.Error()), nil, nil\n\t}","sourceCodeStart":737,"sourceCodeEnd":773,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/github/discussions.go#L737-L773","documentation":"requiredCommentNodeID fetches the commentNodeID argument and rejects values that are empty after strings.TrimSpace. This is intentional input validation: GraphQL mutations (reply, update, delete, mark/unmark answer) need a valid node ID of the form AQAA…(base64). A blank or whitespace-only string is rejected before any network call and surfaced to the caller as a tool error via NewToolResultError.","triggerScenarios":"Invoking reply_to_discussion_comment / update_discussion_comment / delete_discussion_comment / mark_discussion_comment_as_answer / unmark_discussion_comment_as_answer with commentNodeID set to \"\", \"   \", or omitted-but-defaulted by a client that coerces missing params to empty strings; LLM tool callers hallucinating a blank ID; template code substituting an unset variable.","commonSituations":"Prompt-driven agents passing an empty string when they meant to skip the parameter; client SDKs that serialize null as \"\"; copy-paste between tool calls where the node ID variable was never populated from a prior list response.","solutions":["Pass a real node ID obtained from a prior list_discussions / list_discussion_comments call's id field","Trim the input client-side before invoking the tool and skip the call entirely if empty","If the ID comes from templating, assert non-empty at template-render time","Note the difference between blank (this error) and malformed-but-nonblank IDs, which instead fail later at the GraphQL mutation with a NotFound/BadRequest from GitHub"],"exampleFix":"// before: invoking the tool with an unpopulated variable\ncallTool(\"reply_to_discussion_comment\", {\"commentNodeID\": commentID, \"body\": body}) // commentID == \"\"\n\n// after: guard before calling\nif strings.TrimSpace(commentID) == \"\" {\n\treturn errors.New(\"commentNodeID is required: fetch it from list_discussion_comments\")\n}\ncallTool(\"reply_to_discussion_comment\", {\"commentNodeID\": commentID, \"body\": body})","handlingStrategy":"validation","validationCode":"// client-side guard before invoking the tool\ncommentNodeID := strings.TrimSpace(params[\"commentNodeID\"])\nif commentNodeID == \"\" {\n\treturn errors.New(\"commentNodeID is required: get it from list_discussion_comments\")\n}","typeGuard":"func isValidCommentNodeID(s string) bool {\n\ts = strings.TrimSpace(s)\n\treturn len(s) > 0 // GitHub node IDs are opaque base64 strings; shape varies\n}","tryCatchPattern":null,"preventionTips":["Always source node IDs from a prior list/get response field","Trim inputs before calling tools; skip the call when blank","Distinguish blank IDs (rejected locally) from invalid non-blank IDs (rejected by GraphQL mutation)"],"tags":["go","input-validation","discussions","tool-parameters"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}