github/github-mcp-server · warning

failed to marshal discussions: %w

Error message

failed to marshal discussions: %w

What it means

After the list_discussions GraphQL query succeeds, the handler assembles a response map (discussions slice, pageInfo strings/bools, totalCount int) and json.Marshals it. json.Marshal only errors on unsupported values (channels, functions, complex numbers, NaN/Inf floats) or cyclic references; every field here is a plain string/bool/int derived from GraphQL scalars, so this path is defensive and effectively unreachable in practice. If it ever fires, a schema/type change introduced an unmarshalable value.

Source

Thrown at pkg/github/discussions.go:274

				pageInfo = fragment.PageInfo
				totalCount = fragment.TotalCount
			}

			// Create response with pagination info
			response := map[string]any{
				"discussions": discussions,
				"pageInfo": map[string]any{
					"hasNextPage":     pageInfo.HasNextPage,
					"hasPreviousPage": pageInfo.HasPreviousPage,
					"startCursor":     string(pageInfo.StartCursor),
					"endCursor":       string(pageInfo.EndCursor),
				},
				"totalCount": totalCount,
			}

			out, err := json.Marshal(response)
			if err != nil {
				return nil, nil, fmt.Errorf("failed to marshal discussions: %w", err)
			}
			result := utils.NewToolResultText(string(out))
			// Discussion content is user-authored (untrusted); confidentiality
			// follows repo visibility.
			result = attachRepoVisibilityIFCLabelLazy(ctx, deps, owner, repo, result, ifc.LabelRepoUserContent)
			return result, nil, nil
		},
	)
}

func GetDiscussion(t translations.TranslationHelperFunc) inventory.ServerTool {
	return NewTool(
		ToolsetMetadataDiscussions,
		mcp.Tool{
			Name:        "get_discussion",
			Description: t("TOOL_GET_DISCUSSION_DESCRIPTION", "Get a specific discussion by ID"),
			Annotations: &mcp.ToolAnnotations{
				Title:        t("TOOL_GET_DISCUSSION_USER_TITLE", "Get discussion"),

View on GitHub (pinned to 0ea1f775a7)

Solutions

  1. Treat a hit as a code defect: inspect the discussions slice's element types for funcs, channels, or custom MarshalJSON implementations
  2. Add a unit test that marshals a representative response map to catch type regressions in CI
  3. Keep the response composed of primitives (string/int/bool) as it is today
  4. If hit in production, log the payload types (not contents) and fall back to a minimal shape so the tool still returns something useful
Defensive patterns

Strategy: try-catch

Try / catch

out, err := json.Marshal(response)
if err != nil {
	// defensive branch: a failure means a code defect in response construction
	logger.Error("marshal discussions failed", "err", err)
	return nil, nil, fmt.Errorf("failed to marshal discussions: %w", err)
}

Prevention

When it happens

Trigger: A future change storing a githubv4.ID, time.Time with a bad MarshalJSON, or a func/channel inside the discussions slice or pageInfo map; cyclic structures if discussion objects ever reference each other. Not triggerable by any GitHub API response with the current types.

Common situations: Refactors that swap plain strings for typed wrappers with custom marshaling bugs; test code mutating the response shape; library forks adding fields. Real GitHub data (titles, cursors, counts) cannot cause it.

Related errors


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