gastownhall/beads · error
failed to update issue: %w
Error message
failed to update issue: %w
What it means
UpdateIssue builds an issueUpdate GraphQL mutation and executes it via c.Execute; if Execute returns any error (transport failure, HTTP non-2xx, GraphQL errors, parse failure), it is wrapped as 'failed to update issue'. This is the top-level wrapper for all update-path failures; unwrap it to find the root cause.
Source
Thrown at internal/linear/client.go:1010
type
}
updatedAt
}
}
}
`
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 blindlyView on GitHub (pinned to 71377f2769)
Solutions
- Unwrap with errors.As/Unwrap to see whether it's transport, HTTP status, or a GraphQL error
- Verify issueID and all update field values (stateID, assigneeID, labelIDs) are current and in the same workspace
- Handle 429 by throttling bulk updates with backoff
- Ensure the API token has write scopes for issue updates
Example fix
// before
_, err := client.UpdateIssue(ctx, issueID, linear.IssueUpdateInput{StateID: cachedStateID})
// after
stateID := refreshStateIDFromAPI(ctx, client, teamID) // don't trust stale cached IDs
_, err := client.UpdateIssue(ctx, issueID, linear.IssueUpdateInput{StateID: stateID})
if err != nil {
var ge *linear.GraphQLError
if errors.As(err, &ge) { /* handle field-specific GraphQL error */ }
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify the issue still exists and IDs are valid before updating
issues, err := client.SearchIssues(ctx, fmt.Sprintf("id: %s", issueID))
if err != nil || len(issues) == 0 {
return fmt.Errorf("issue %s not found, skipping update", issueID)
} Try / catch
_, err := client.UpdateIssue(ctx, issueID, updates)
if err != nil {
unwrapped := fmt.Errorf("%v", errors.Unwrap(err))
switch {
case strings.Contains(unwrapped.Error(), "status 429"):
backoffAndRetry()
case strings.Contains(unwrapped.Error(), "GraphQL errors"):
log.Printf("update rejected, check IDs/scopes: %v", unwrapped)
default:
return err
}
} Prevention
- Re-fetch issue IDs near update time instead of long-lived caches
- Throttle bulk updates to stay under Linear rate limits
- Ensure the token has issue write scopes
- Handle deleted/archived issues gracefully in automations
When it happens
Trigger: Invalid issueID (nonexistent/archived issue) producing a GraphQL error; trying to set an invalid stateID/label/assignee in updates; network failure or 429 rate limit during the mutation; token lacking update scope.
Common situations: Issue deleted or moved to trash by a user while the automation was running; stale IDs cached from earlier queries; bulk update loops tripping Linear's rate limiter; integration tokens without write scope.
Related errors
- GraphQL error: %s
- failed to fetch team states: %w
- failed to update project: %w
- failed to list projects: %w
- node %q: updating metadata refs: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d72edf9327a997da.
Report an issue: GitHub.