gastownhall/beads · error
oauth: token request failed: %w
Error message
oauth: token request failed: %w
What it means
The OAuth token HTTP request itself failed at the transport level (connection refused, DNS failure, TLS error, timeout). The authorization server was unreachable, so no token could be issued.
Source
Thrown at internal/linear/oauth.go:131
// acquireToken performs the client_credentials grant. Caller must hold m.mu write lock.
func (m *OAuthTokenManager) acquireToken() error {
data := url.Values{
"grant_type": {"client_credentials"},
"client_id": {m.config.ClientID},
"client_secret": {m.config.ClientSecret},
"scope": {m.config.Scopes},
"actor": {m.config.Actor},
}
req, err := http.NewRequest("POST", m.config.TokenURL, strings.NewReader(data.Encode()))
if err != nil {
return fmt.Errorf("oauth: failed to create token request: %w", err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := m.client.Do(req)
if err != nil {
return fmt.Errorf("oauth: token request failed: %w", err)
}
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) // 1MB limit
if err != nil {
return fmt.Errorf("oauth: failed to read token response: %w", err)
}
if resp.StatusCode != http.StatusOK {
var errResp oauthErrorResponse
if json.Unmarshal(body, &errResp) == nil && errResp.Error != "" {
return fmt.Errorf("oauth: token request failed (%s): %s", errResp.Error, errResp.Description)
}
return fmt.Errorf("oauth: token request returned status %d: %s", resp.StatusCode, string(body))
}
var tokenResp oauthTokenResponse
if err := json.Unmarshal(body, &tokenResp); err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Check network egress and proxy settings (HTTPS_PROXY) from the host running the code.
- Verify TokenURL hostname resolves and is reachable (curl -v the endpoint).
- Increase the HTTP client timeout if the failure is a timeout on a slow network.
- Configure the http.Client's TLS settings if a corporate MITM certificate is in play.
Example fix
// before
client: &http.Client{}
// after
client: &http.Client{
Timeout: 15 * time.Second,
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
} Defensive patterns
Strategy: retry
Try / catch
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// retry with exponential backoff
}
// otherwise surface the wrapped oauth error to the operator Prevention
- Set a sane HTTP client timeout and enable proxy-from-environment.
- Monitor egress connectivity to the token endpoint in health checks.
- Retry idempotent token fetches with jittered backoff.
When it happens
Trigger: m.client.Do(req) returns an error inside acquireToken during a client-credentials token exchange.
Common situations: Corporate proxy or firewall blocking the token endpoint; DNS outage; TLS cert issues (self-signed MITM proxies); TokenURL pointing at a wrong host or a dead internal endpoint.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- failed to remove backup: %w
- ensureProxiedServerConfig: pick free port: %w
- pull: %w
- push: %w
- failed to summarize: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/9a17a4538e292ec7.
Report an issue: GitHub.