gastownhall/beads · error

failed to fetch teams: %w

Error message

failed to fetch teams: %w

What it means

FetchTeams queries the teams GraphQL field to discover team IDs. This error wraps any Execute failure — network errors, HTTP status errors, GraphQL errors like insufficient scopes — when listing teams. It is typically the first call made when configuring the integration, so it is the first place auth problems surface.

Source

Thrown at internal/linear/client.go:1428

	query := `
		query {
			teams {
				nodes {
					id
					name
					key
				}
			}
		}
	`

	req := &GraphQLRequest{
		Query: query,
	}

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

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

	return teamsResp.Teams.Nodes, nil
}

// FetchProjects retrieves projects from Linear with optional filtering by state.
// state can be: "planned", "started", "paused", "completed", "canceled", or "all"/"".
func (c *Client) FetchProjects(ctx context.Context, state string) ([]Project, error) {
	var allProjects []Project
	var cursor string

	filter := map[string]interface{}{
		"team": map[string]interface{}{

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the error to identify the underlying cause (status code / GraphQL message).
  2. Verify the API key in Linear settings → API; regenerate if revoked and update the environment/config.
  3. Test connectivity: curl the Linear GraphQL endpoint from the same host.
  4. Check for 429 rate-limit errors and add backoff/retry around the call.
  5. Ensure the token's OAuth scopes include team read access.

Example fix

// before
team, err := client.FetchTeams(ctx)
// after
team, err := client.FetchTeams(ctx)
if err != nil {
    var rl *RateLimitError
    if errors.As(err, &rl) { time.Sleep(rl.RetryAfter); return client.FetchTeams(ctx) }
    return fmt.Errorf("team discovery failed (check LINEAR_API_KEY): %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// sanity-check configuration before calling
if os.Getenv("LINEAR_API_KEY") == "" {
    return fmt.Errorf("LINEAR_API_KEY not set")
}
if len(os.Getenv("LINEAR_API_KEY")) < 20 {
    return fmt.Errorf("LINEAR_API_KEY looks truncated")
}

Try / catch

teams, err := client.FetchTeams(ctx)
if err != nil {
    if strings.Contains(err.Error(), "401") || strings.Contains(err.Error(), "authentication") {
        return fmt.Errorf("invalid or expired Linear API key: %w", err)
    }
    if isRetryable(err) {
        return retryWithBackoff(3, 2*time.Second, func() error {
            _, err = client.FetchTeams(ctx); return err
        })
    }
    return err
}

Prevention

When it happens

Trigger: c.Execute fails on `query { teams { nodes { id name key } } }`: invalid/expired API key (401), token missing teams read scope, rate limiting, network unreachable, or context cancellation.

Common situations: Initial setup with a mistyped LINEAR_API_KEY; org admin revoked the integration token; workspace SSO enforcing token rotation; firewall blocking linear.app; expired OAuth token in a long-lived daemon.

Related errors


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