github/github-mcp-server · error

failed to marshal workflow run: %w

Error message

failed to marshal workflow run: %w

What it means

Defensive guard in getWorkflowRun (pkg/github/actions.go:807): json.Marshal of convertToMinimalWorkflowRun(workflowRun) failed. The conversion produces a server-owned minimal struct of scalar fields, so this is effectively unreachable unless a regression adds a non-serializable value (func, chan, NaN, cycle) to that struct.

Source

Thrown at pkg/github/actions.go:807

	defer func() { _ = resp.Body.Close() }()
	r, err := json.Marshal(workflow)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to marshal workflow: %w", err)
	}

	return utils.NewToolResultText(string(r)), nil, nil
}

func getWorkflowRun(ctx context.Context, client *github.Client, owner, repo string, resourceID int64) (*mcp.CallToolResult, any, error) {
	workflowRun, resp, err := client.Actions.GetWorkflowRunByID(ctx, owner, repo, resourceID)
	if err != nil {
		return ghErrors.NewGitHubAPIErrorResponse(ctx, "failed to get workflow run", resp, err), nil, nil
	}
	defer func() { _ = resp.Body.Close() }()
	r, err := json.Marshal(convertToMinimalWorkflowRun(workflowRun))
	if err != nil {
		return nil, nil, fmt.Errorf("failed to marshal workflow run: %w", err)
	}
	return utils.NewToolResultText(string(r)), nil, nil
}

func getWorkflowJob(ctx context.Context, client *github.Client, owner, repo string, resourceID int64) (*mcp.CallToolResult, any, error) {
	workflowJob, resp, err := client.Actions.GetWorkflowJobByID(ctx, owner, repo, resourceID)
	if err != nil {
		return ghErrors.NewGitHubAPIErrorResponse(ctx, "failed to get workflow job", resp, err), nil, nil
	}
	defer func() { _ = resp.Body.Close() }()
	r, err := json.Marshal(workflowJob)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to marshal workflow job: %w", err)
	}
	return utils.NewToolResultText(string(r)), nil, nil
}

func listWorkflows(ctx context.Context, client *github.Client, owner, repo string, pagination PaginationParams) (*mcp.CallToolResult, any, error) {

View on GitHub (pinned to 0ea1f775a7)

Solutions

  1. Report upstream if hit with a stock release - include run ID and versions
  2. Keep the minimal struct scalar-only (string, int, bool, time as string)
  3. Unit-test the conversion plus marshal path
  4. Pin known-good versions

Example fix

// before
r, err := json.Marshal(convertToMinimalWorkflowRun(workflowRun))
if err != nil {
    return nil, nil, fmt.Errorf("failed to marshal workflow run: %w", err)
}

// after - guard the conversion itself with a test-friendly error
minimal := convertToMinimalWorkflowRun(workflowRun)
r, err := json.Marshal(minimal)
if err != nil {
    return nil, nil, fmt.Errorf("failed to marshal workflow run (run %d): %w", workflowRun.GetID(), err)
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the converted struct is JSON-safe in tests
func TestMinimalWorkflowRunMarshal(t *testing.T) {
    if _, err := json.Marshal(convertToMinimalWorkflowRun(&github.WorkflowRun{})); err != nil {
        t.Fatalf("minimal run not JSON-safe: %v", err)
    }
}

Try / catch

if err != nil {
    reportIssue("get_action_workflow_run", map[string]any{"run_id": runID}, err, version())
    return err
}

Prevention

When it happens

Trigger: Calling get_action_workflow_run with a valid run ID after code changes made convertToMinimalWorkflowRun emit JSON-unsafe values; NaN timestamps/durations introduced by timezone or duration math bugs.

Common situations: Not seen in stock releases; a hazard only for forks that extend the minimal-run struct.

Related errors


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