gastownhall/beads · error
failed to parse description search response: %w
Error message
failed to parse description search response: %w
What it means
Once the description-search query succeeds, the response bytes are unmarshalled into IssuesResponse. This error wraps a JSON unmarshal failure, meaning the HTTP call worked but the body does not match the expected `{ issues: { nodes: [...] } }` shape.
Source
Thrown at internal/linear/client.go:786
"contains": text,
},
}
req := &GraphQLRequest{
Query: query,
Variables: map[string]interface{}{
"filter": filter,
},
}
data, err := c.Execute(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to search issues by description: %w", err)
}
var issuesResp IssuesResponse
if err := json.Unmarshal(data, &issuesResp); err != nil {
return nil, fmt.Errorf("failed to parse description search response: %w", err)
}
if len(issuesResp.Issues.Nodes) > 0 {
return &issuesResp.Issues.Nodes[0], nil
}
return nil, nil
}
// issueCreateMutation is the GraphQL mutation for creating a Linear issue.
const issueCreateMutation = `
mutation CreateIssue($input: IssueCreateInput!) {
issueCreate(input: $input) {
success
issue {
id
identifier
title
descriptionView on GitHub (pinned to 71377f2769)
Solutions
- Log the raw response body alongside the unmarshal error to see the actual payload.
- Confirm the endpoint URL is https://api.linear.app/graphql.
- Check for and surface any GraphQL `errors` array in the response before/instead of unmarshalling.
- Update IssuesResponse struct fields if the Linear schema changed.
Example fix
// before
if err := json.Unmarshal(data, &issuesResp); err != nil {
return nil, fmt.Errorf("failed to parse description search response: %w", err)
}
// after
if err := json.Unmarshal(data, &issuesResp); err != nil {
return nil, fmt.Errorf("failed to parse description search response: %w (body: %.200s)", err, data)
} Defensive patterns
Strategy: type-guard
Validate before calling
// verify endpoint before search
if client.Endpoint != "https://api.linear.app/graphql" {
return errors.New("unexpected Linear endpoint")
} Type guard
func validIssuesPayload(data []byte) bool {
var probe struct {
Issues *struct {
Nodes []json.RawMessage `json:"nodes"`
} `json:"issues"`
}
return json.Unmarshal(data, &probe) == nil && probe.Issues != nil
} Try / catch
issue, err := client.FindIssueByDescriptionContains(ctx, desc)
if err != nil {
var typeErr *json.UnmarshalTypeError
if errors.As(err, &typeErr) {
log.Printf("unexpected search response shape at %s; skipping dedupe", typeErr.Field)
return nil // proceed without dedupe or use cache
}
return err
} Prevention
- Log raw response bodies when parsing fails.
- Block HTML error pages by checking Content-Type before unmarshal.
- Add golden-file tests decoding real Linear responses.
- Monitor Linear API changelog for issues-connection changes.
When it happens
Trigger: Linear returns 200 with a body that doesn't fit IssuesResponse — GraphQL error partial payloads, schema changes to the issues connection, proxy/HTML error bodies with a 200 status, or truncated responses.
Common situations: Hitting the wrong endpoint (REST instead of /graphql), corporate proxies returning HTML interstitials, Linear schema updates renaming `issues` or `nodes`, mid-request connection drops producing truncated JSON.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse team labels response: %w
- failed to parse create response: %w
- failed to parse update project response: %w
- existing milestone metadata is not a JSON object: %w
- marshaling Linear milestone metadata: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/1f4004b6bd836941.
Report an issue: GitHub.