github/github-mcp-server · warning

failed to marshal discussion: %w

Error message

failed to marshal discussion: %w

What it means

get_discussion marshals a map of primitives (id, title, URLs, category name, optional answerChosenAt time.Time) after a successful GraphQL query. The only realistically marshalable-risk value is the time.Time from d.AnswerChosenAt.Time, whose default encoding never fails; everything else is strings. json.Marshal errors require unsupported types or cycles, so this is a defensive guard that current data shapes cannot trip.

Source

Thrown at pkg/github/discussions.go:381

				"title":      string(d.Title),
				"body":       string(d.Body),
				"url":        string(d.URL),
				"closed":     bool(d.Closed),
				"isAnswered": bool(d.IsAnswered),
				"createdAt":  d.CreatedAt.Time,
				"category": map[string]any{
					"name": string(d.Category.Name),
				},
			}

			// Add optional timestamp fields if present
			if d.AnswerChosenAt != nil {
				response["answerChosenAt"] = d.AnswerChosenAt.Time
			}

			out, err := json.Marshal(response)
			if err != nil {
				return nil, nil, fmt.Errorf("failed to marshal discussion: %w", err)
			}

			result := utils.NewToolResultText(string(out))
			// Discussion content is user-authored (untrusted); confidentiality
			// follows repo visibility.
			result = attachRepoVisibilityIFCLabelLazy(ctx, deps, params.Owner, params.Repo, result, ifc.LabelRepoUserContent)
			return result, nil, nil
		},
	)
}

func GetDiscussionComments(t translations.TranslationHelperFunc) inventory.ServerTool {
	return NewTool(
		ToolsetMetadataDiscussions,
		mcp.Tool{
			Name:        "get_discussion_comments",
			Description: t("TOOL_GET_DISCUSSION_COMMENTS_DESCRIPTION", "Get comments from a discussion"),
			Annotations: &mcp.ToolAnnotations{

View on GitHub (pinned to 0ea1f775a7)

Solutions

  1. Verify every value in the response map is string/int/bool or time.Time, converting GraphQL scalar types with string(...)/fmt.Sprintf as the current code does
  2. Add a golden JSON test for the get_discussion response shape
  3. If it fires, it is a bug in this handler's construction, not in input data; check recent diffs to the response map
  4. Return a degraded minimal response (id + url) rather than failing the whole tool if a marshaling regression is suspected
Defensive patterns

Strategy: try-catch

Try / catch

out, err := json.Marshal(response)
if err != nil {
	return nil, nil, fmt.Errorf("failed to marshal discussion: %w", err)
}

Prevention

When it happens

Trigger: Introduction of a non-marshalable field (channel, func, NaN float) into the response map in a refactor; a custom type with a broken MarshalJSON replacing string(d.Category.Name); cyclic data if discussion maps ever embed each other. No GitHub response triggers it today.

Common situations: Forks extending the response with typed objects; copy-paste of GraphQL struct fields (which carry extra methods) into the map instead of converting to strings; regressions after go-github/githubv4 upgrades that change field types.

Related errors


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