bytebase/bytebase · error

failed to construct token request

Error message

failed to construct token request

What it means

The Teams webhook plugin's getToken builds the OAuth2 client-credentials token request to Microsoft's token endpoint (http.NewRequestWithContext with a form-encoded body). If constructing that request object fails, this error wraps the underlying cause. http.NewRequest only fails on an invalid URL/method or a malformed body reader, so this almost always indicates a bad tokenURL configuration value.

Source

Thrown at backend/plugin/webhook/teams/app.go:100

const (
	graphScope = "https://graph.microsoft.com/.default"
	botScope   = "https://api.botframework.com/.default"
)

// getToken fetches an OAuth2 token using client credentials flow.
func getToken(ctx context.Context, c *http.Client, tenantID, clientID, clientSecret, scope string) (*tokenValue, error) {
	tokenURL := fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantID)

	data := url.Values{}
	data.Set("client_id", clientID)
	data.Set("client_secret", clientSecret)
	data.Set("scope", scope)
	data.Set("grant_type", "client_credentials")

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, tokenURL, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, errors.Wrapf(err, "failed to construct token request")
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := c.Do(req)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to request token")
	}
	defer resp.Body.Close()

	b, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to read token response")
	}

	if resp.StatusCode != http.StatusOK {
		return nil, errors.Errorf("token request failed (status %d): %s", resp.StatusCode, string(b))
	}

View on GitHub (pinned to 1870550677)

Solutions

  1. Check the wrapped error for the url.Parse failure message identifying the bad URL
  2. Verify the configured token endpoint is a full absolute https:// URL (default: https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token)
  3. Fix the Teams app configuration in Bytebase settings
  4. Restart/resend the webhook so getTokenCached builds a fresh request

Example fix

// before
// tokenURL configured as "login.microsoftonline.com/<tenant>/oauth2/v2.0/token" (no scheme)
// after
// tokenURL configured as "https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(tokenURL)
if err != nil || u.Scheme != "https" || u.Host == "" {
	return fmt.Errorf("invalid token URL: %q", tokenURL)
}

Try / catch

// Go: check the wrapped url.Parse error to identify the malformed URL
if _, err := url.Parse(cfg.TokenURL); err != nil {
	return errors.Wrapf(err, "invalid teams token url %q", cfg.TokenURL)
}

Prevention

When it happens

Trigger: getToken is called (via getTokenCached) when a cached Graph token is missing or expired; http.NewRequestWithContext returns an error, typically because the Teams plugin's tenant/token URL setting is malformed (e.g. missing scheme, control characters) and url.Parse fails.

Common situations: Admin misconfigured the Teams app endpoint (typo in https://, empty string interpolated into the URL); environment-level proxy settings or config templating produced an invalid URL; an old Bytebase config from an endpoint scheme change.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/a7c4476dbac56cda. Report an issue: GitHub.