github/github-mcp-server · error
failed to marshal workflow runs: %w
Error message
failed to marshal workflow runs: %w
What it means
json.Marshal failed while serializing the trimmed workflow-run list produced by convertToMinimalWorkflowRuns after a successful ListWorkflowRunsByID/ListWorkflowRunsByFileName call. encoding/json only fails on values it cannot represent: channels, functions, complex numbers, cyclic data structures, or float NaN/Inf (json.UnsupportedTypeError / json.UnsupportedValueError). Because the payload is maps/structs of strings, ints and timestamps built from go-github types, this branch is defensive and should never fire on a healthy release.
Source
Thrown at pkg/github/actions.go:889
var workflowRuns *github.WorkflowRuns
var resp *github.Response
if resourceID == "" {
workflowRuns, resp, err = client.Actions.ListRepositoryWorkflowRuns(ctx, owner, repo, listWorkflowRunsOptions)
} else if workflowIDInt, parseErr := strconv.ParseInt(resourceID, 10, 64); parseErr == nil {
workflowRuns, resp, err = client.Actions.ListWorkflowRunsByID(ctx, owner, repo, workflowIDInt, listWorkflowRunsOptions)
} else {
workflowRuns, resp, err = client.Actions.ListWorkflowRunsByFileName(ctx, owner, repo, resourceID, listWorkflowRunsOptions)
}
if err != nil {
return ghErrors.NewGitHubAPIErrorResponse(ctx, "failed to list workflow runs", resp, err), nil, nil
}
defer func() { _ = resp.Body.Close() }()
r, err := json.Marshal(convertToMinimalWorkflowRuns(workflowRuns))
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal workflow runs: %w", err)
}
return utils.NewToolResultText(string(r)), nil, nil
}
func listWorkflowJobs(ctx context.Context, client *github.Client, args map[string]any, owner, repo string, resourceID int64, pagination PaginationParams) (*mcp.CallToolResult, any, error) {
filterArgs, err := OptionalParam[map[string]any](args, "workflow_jobs_filter")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}
filterArgsTyped := make(map[string]string)
for k, v := range filterArgs {
if strVal, ok := v.(string); ok {
filterArgsTyped[k] = strVal
} else {
filterArgsTyped[k] = ""
}View on GitHub (pinned to 0ea1f775a7)
Solutions
- Inspect the wrapped error: json.UnsupportedTypeError names the exact Go type and field path that broke marshaling — fix or stringify that field in convertToMinimalWorkflowRuns
- Update the go-github dependency and github-mcp-server to matching versions so the struct shape matches what GitHub returns
- Sanitize the converted runs before marshaling (drop or fmt.Sprintf non-JSON types, clamp NaN/Inf floats)
- Re-run the tool once to rule out a one-off corrupted response
Example fix
// before
r, err := json.Marshal(convertToMinimalWorkflowRuns(workflowRuns))
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal workflow runs: %w", err)
}
// after — surface the offending type and return a tool-safe error
runs := convertToMinimalWorkflowRuns(workflowRuns)
r, err := json.Marshal(runs)
if err != nil {
var unsupported *json.UnsupportedTypeError
if errors.As(err, &unsupported) {
slog.Error("unmarshalable workflow run payload", "type", unsupported.Type.String())
}
return utils.NewToolResultError(fmt.Sprintf("failed to serialize workflow runs: %v", err)), nil, nil
} Defensive patterns
Strategy: try-catch
Type guard
func isJSONMarshalable(v any) bool {
switch v.(type) {
case chan struct{}, func(), complex128, complex64:
return false
}
return true
} Try / catch
r, err := json.Marshal(runs)
if err != nil {
var unsupported *json.UnsupportedTypeError
var value *json.UnsupportedValueError
switch {
case errors.As(err, &unsupported):
// upstream type drift: log unsupported.Type and degrade gracefully
case errors.As(err, &value):
// NaN/Inf: sanitize numeric fields and retry once
default:
return fmt.Errorf("failed to marshal workflow runs: %w", err)
}
} Prevention
- Keep go-github and github-mcp-server versions aligned in go.mod — struct drift is the main realistic cause
- In forks, restrict converter output to strings, numbers, booleans, and time.Time
- Add a unit test asserting convertToMinimalWorkflowRuns output marshals for representative fixtures
When it happens
Trigger: Calling list_workflow_runs (or list_workflow_runs_by_filename) and reaching the final json.Marshal with a payload containing a non-JSON-representable value — e.g. an upstream go-github version bump that added a func/chan/complex-typed field copied through the minimal-runs converter, or a fork that passes timestamps.Float64 values that are NaN.
Common situations: Pinned/old go-github dependency whose structs diverge from the API payload, custom forks extending convertToMinimalWorkflowRuns with unsupported types, or corrupted in-memory data after a partial API response.
Related errors
- failed to marshal response: %w
- failed to marshal workflow jobs: %w
- GitHub App authentication and GITHUB_PERSONAL_ACCESS_TOKEN a
- GitHub App ID or client ID is required (GITHUB_APP_ID)
- repo is required
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/2558378e61bcb58d.
Report an issue: GitHub.