gastownhall/beads · error

failed to parse update response: %w

Error message

failed to parse update response: %w

What it means

UpdateIssue calls the Linear issueUpdate GraphQL mutation via c.Execute and then json.Unmarshals the returned raw JSON into IssueUpdateResponse. This error means the HTTP call succeeded but the response body could not be decoded into the expected envelope (missing issueUpdate field, unexpected shape, or non-JSON payload such as an HTML error page from a proxy). The library throws it to distinguish transport failures from parse failures.

Source

Thrown at internal/linear/client.go:1015

		}
	`

	req := &GraphQLRequest{
		Query: query,
		Variables: map[string]interface{}{
			"id":    issueID,
			"input": updates,
		},
	}

	data, err := c.Execute(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to update issue: %w", err)
	}

	var updateResp IssueUpdateResponse
	if err := json.Unmarshal(data, &updateResp); err != nil {
		return nil, fmt.Errorf("failed to parse update response: %w", err)
	}

	if !updateResp.IssueUpdate.Success {
		return nil, fmt.Errorf("issue update reported as unsuccessful")
	}

	return &updateResp.IssueUpdate.Issue, nil
}

// BatchCreateIssues creates multiple issues in Linear using the issueBatchCreate mutation.
// Inputs are chunked into groups of BatchSize (50).
//
// On ambiguous failure (API error or success=false), this method does NOT blindly
// retry the full chunk—Linear may have partially applied the mutation. Instead it
// searches for each issue's idempotency marker (embedded in the description) to
// discover which issues were actually created, and returns an error for the rest.
func (c *Client) BatchCreateIssues(ctx context.Context, inputs []IssueCreateInput) ([]Issue, error) {
	if len(inputs) == 0 {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Print/log the raw response (data) alongside the wrapped error to see what actually came back before changing code.
  2. Retry UpdateIssue; a truncated or proxy-generated body is usually transient.
  3. Verify you are on a recent version of the library matching the current Linear GraphQL schema.
  4. Check network middleboxes (corporate proxy, API gateway) that can substitute HTML error bodies for JSON.

Example fix

// before
issue, err := client.UpdateIssue(ctx, issueID, updates)
if err != nil {
    return err
}
// after
issue, err := client.UpdateIssue(ctx, issueID, updates)
if err != nil {
    if strings.Contains(err.Error(), "failed to parse update response") {
        // inspect raw payload / retry transient parse failures
        return fmt.Errorf("linear update response undecodable: %w", err)
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No pre-call validation can detect a bad response body; ensure inputs are JSON-serializable
if updates == nil {
    return errors.New("updates input must not be nil")
}

Try / catch

issue, err := client.UpdateIssue(ctx, id, updates)
if err != nil {
    if strings.Contains(err.Error(), "failed to parse update response") {
        // transient/undecodable body: log raw payload if available, retry once
        return retryUpdate(ctx, client, id, updates)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Client.UpdateIssue(ctx, issueID, updates) when Linear (or an intermediary) returns a body that is not valid JSON or does not match the IssueUpdateResponse struct (e.g. a partial success payload, an HTML gateway error page, or a changed GraphQL schema).

Common situations: Corporate proxies or load balancers returning HTML 502/503 pages with HTTP 200-style handling; Linear API schema changes renaming issueUpdate; truncated response bodies on flaky networks; a custom HTTP transport in tests returning unexpected fixtures.

Understand the failure class

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/c611f182022198b5. Report an issue: GitHub.