gastownhall/beads · error
failed to update project: %w
Error message
failed to update project: %w
What it means
UpdateProject wraps any error returned by the GraphQL Execute call (network failure, HTTP error, or GraphQL errors array) with the context 'failed to update project'. The underlying error is preserved via %w so callers can unwrap with errors.Is/As. It signals the Linear API rejected or never received the project mutation.
Source
Thrown at internal/linear/client.go:1579
state
progress
updatedAt
}
}
}
`
req := &GraphQLRequest{
Query: query,
Variables: map[string]interface{}{
"id": projectID,
"input": updates,
},
}
data, err := c.Execute(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to update project: %w", err)
}
var updateResp ProjectUpdateResponse
if err := json.Unmarshal(data, &updateResp); err != nil {
return nil, fmt.Errorf("failed to parse update project response: %w", err)
}
if !updateResp.ProjectUpdate.Success {
return nil, fmt.Errorf("project update reported as unsuccessful")
}
return &updateResp.ProjectUpdate.Project, nil
}
View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error with errors.Unwrap (or %v logging) to see the actual transport/GraphQL failure.
- Verify the Linear API key is valid and has access to the target project/team.
- Check that the project ID passed to UpdateProject still exists (fetch it first via the API).
- Retry with backoff if the wrapped error is a 429 rate-limit or transient network error.
- Check Linear's status page for API outages.
Example fix
// before
project, err := client.UpdateProject(ctx, id, updates)
if err != nil {
log.Fatal(err)
}
// after
project, err := client.UpdateProject(ctx, id, updates)
if err != nil {
var gqlErr *linear.GraphQLError
if errors.As(err, &gqlErr) {
log.Fatalf("linear rejected project update: %v", gqlErr)
}
if errors.Is(err, context.DeadlineExceeded) {
log.Fatal("linear API timed out; retry later")
}
log.Fatal(err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if projectID == "" {
return fmt.Errorf("project ID required before UpdateProject")
}
if client == nil || apiKey == "" {
return fmt.Errorf("linear client/key must be configured before UpdateProject")
} Try / catch
project, err := client.UpdateProject(ctx, id, updates)
if err != nil {
var netErr net.Error
switch {
case errors.As(err, &netErr) || errors.Is(err, context.DeadlineExceeded):
// retry with backoff
case strings.Contains(err.Error(), "429"):
// honor rate limit, retry later
default:
return fmt.Errorf("update project %s: %w", id, err)
}
} Prevention
- Always unwrap/log the wrapped cause before reporting, since %w preserves the real error.
- Validate project IDs exist (via a fetch) before updating.
- Keep the API key in env/secret store and rotate before expiry.
- Implement backoff retry for 429 and transient network errors.
- Pin and monitor the Linear API version you depend on.
When it happens
Trigger: Calling linear Client.UpdateProject when the Linear API is unreachable, the API key is invalid/expired, the project ID does not exist, a rate limit is hit, or the GraphQL response carries an errors array.
Common situations: Revoked Linear API keys, offline/timeout network conditions, updating a project that was deleted or that the integration token cannot access, Linear API downtime, exceeded GraphQL complexity or rate limits.
Related errors
- failed to fetch issues: %w
- failed to fetch issues since %s: %w
- failed to fetch team states: %w
- failed to fetch team labels: %w
- failed to search issues by description: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/0254751ae841ca8d.
Report an issue: GitHub.