gastownhall/beads · error

failed to get OAuth token: %w

Error message

failed to get OAuth token: %w

What it means

When the Linear client is in OAuth auth mode, authHeader obtains an access token from the client's TokenManager to build the Authorization header. If the token manager cannot produce a token (refresh failure, expired refresh token, network problem reaching the token endpoint), the error is wrapped as 'failed to get OAuth token'. It propagates to executeOnce and createIssueSingleAttempt, which surface it to the caller.

Source

Thrown at internal/linear/client.go:214

		APIKey:         c.APIKey,
		TeamID:         c.TeamID,
		ProjectID:      projectID,
		Endpoint:       c.Endpoint,
		HTTPClient:     c.HTTPClient,
		AuthMode:       c.AuthMode,
		TokenManager:   c.TokenManager,
		RateLimitFloor: c.RateLimitFloor,
		rateLimitState: c.rateLimitState,
	}
}

// authHeader returns the Authorization header value for this client.
func (c *Client) authHeader() (string, error) {
	switch c.AuthMode {
	case AuthModeOAuth:
		token, err := c.TokenManager.Token()
		if err != nil {
			return "", fmt.Errorf("failed to get OAuth token: %w", err)
		}
		return "Bearer " + token, nil
	default:
		return c.APIKey, nil
	}
}

// WithRateLimitFloor returns a new client with the specified rate-limit circuit-breaker floor.
// When remaining API quota drops below this value, Execute returns ErrRateLimitExhausted.
func (c *Client) WithRateLimitFloor(floor int) *Client {
	return &Client{
		APIKey:         c.APIKey,
		TeamID:         c.TeamID,
		ProjectID:      c.ProjectID,
		Endpoint:       c.Endpoint,
		HTTPClient:     c.HTTPClient,
		AuthMode:       c.AuthMode,
		TokenManager:   c.TokenManager,

View on GitHub (pinned to 71377f2769)

Solutions

  1. Re-authenticate the OAuth integration to obtain a fresh refresh token
  2. Check the wrapped (%w) inner error — refresh failure vs network — and fix accordingly
  3. Verify the token endpoint is reachable (proxy/firewall/DNS)
  4. Alternatively configure API-key auth mode if OAuth is not required
  5. Ensure the system clock is correct
Defensive patterns

Strategy: try-catch

Validate before calling

if client.AuthMode == linear.AuthModeOAuth {
	if _, err := client.TokenManager.Token(); err != nil {
		return fmt.Errorf("OAuth not usable: %w", err)
	}
}

Try / catch

data, err := client.Execute(ctx, req)
if err != nil {
	var tokErr *fmt.WrapError // or errors.As on the underlying token error
	if errors.Is(err, oauth.ErrTokenExpired) || strings.Contains(err.Error(), "failed to get OAuth token") {
		if rerr := refreshCredentials(ctx); rerr != nil { return rerr }
		data, err = client.Execute(ctx, req)
	}
	if err != nil { return err }
}

Prevention

When it happens

Trigger: Any API call (Execute / createIssueSingleAttempt) with c.AuthMode == AuthModeOAuth where TokenManager.Token() fails — e.g. expired access token with failed refresh, revoked refresh token, or unreachable OAuth token endpoint.

Common situations: Long-running processes whose refresh token expired; revoked OAuth app credentials; corporate proxy blocking the token endpoint; clock skew causing premature token expiry; switching between API-key and OAuth config without updating AuthMode.

Related errors


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