gastownhall/beads · error

failed to fetch teams

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.

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.

Appendix: 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)