gastownhall/beads · error

failed to fetch team states: %w

Error message

failed to fetch team states: %w

What it means

GetTeamStates wraps any Execute failure with this message when fetching a team's workflow states. The wrapped cause is the underlying failure: GraphQL error (usually an unknown team ID), auth failure, rate limiting, or network error. Callers like BuildStateCache depend on this succeeding to map states.

Source

Thrown at internal/linear/client.go:645

						id
						name
						type
					}
				}
			}
		}
	`

	req := &GraphQLRequest{
		Query: query,
		Variables: map[string]interface{}{
			"teamId": c.TeamID,
		},
	}

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

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

	if teamResp.Team.States == nil {
		return nil, fmt.Errorf("no states found for team")
	}

	return teamResp.Team.States.Nodes, nil
}

// GetTeamLabels returns all issue labels defined for the team (paginated).
func (c *Client) GetTeamLabels(ctx context.Context) ([]Label, error) {
	const pageSize = 250
	query := `

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped cause — 'GraphQL errors: Team not found' almost always means TeamID is wrong
  2. Verify the team ID by querying Linear for the workspace's teams with the same token
  3. Regenerate/replace the API key if the wrapped error is 401/403
  4. Wait for rate-limit reset if the cause is 'max retries' / 'rate limited'
  5. Confirm the token's scopes include read access to workflow states

Example fix

// before
states, err := client.GetTeamStates(ctx)
// after: distinguish bad team ID from transient failures
if err != nil {
    if strings.Contains(err.Error(), "not found") {
        log.Fatalf("TeamID %q invalid — list teams with the same token", client.TeamID)
    }
    return fmt.Errorf("transient, retry later: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate team access before building the state cache
probe := `query { viewer { id } }`
if _, err := client.Execute(ctx, &linear.GraphQLRequest{Query: probe}); err != nil {
    return fmt.Errorf("token or connectivity invalid before GetTeamStates: %w", err)
}
if client.TeamID == "" {
    return errors.New("linear: TeamID must be configured")
}

Try / catch

states, err := client.GetTeamStates(ctx)
if err != nil {
    if strings.Contains(err.Error(), "not found") || strings.Contains(err.Error(), "GraphQL errors") {
        return fmt.Errorf("configuration error (TeamID=%q): %w", client.TeamID, err) // no retry
    }
    return retryWithBackoff(ctx, func() ([]linear.State, error) { return client.GetTeamStates(ctx) })
}

Prevention

When it happens

Trigger: Calling GetTeamStates (directly or via BuildStateCache) when: the configured TeamID doesn't exist in the workspace (Linear returns 'Team not found' GraphQL error), the API token lacks access to that team, OAuth token refresh failed on 401, or Linear is rate-limiting/unreachable.

Common situations: Misconfigured LINEAR_TEAM_ID (typo or ID from another workspace); token created before the team existed or without team access; hitting rate limits right after a large sync; Linear outage.

Related errors


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