{"record":{"id":"a7c4476dbac56cda","repo":"bytebase/bytebase","slug":"failed-to-construct-token-request","errorCode":null,"errorMessage":"failed to construct token request","messagePattern":"failed to construct token request","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/webhook/teams/app.go","lineNumber":100,"sourceCode":"\nconst (\n\tgraphScope = \"https://graph.microsoft.com/.default\"\n\tbotScope   = \"https://api.botframework.com/.default\"\n)\n\n// getToken fetches an OAuth2 token using client credentials flow.\nfunc getToken(ctx context.Context, c *http.Client, tenantID, clientID, clientSecret, scope string) (*tokenValue, error) {\n\ttokenURL := fmt.Sprintf(\"https://login.microsoftonline.com/%s/oauth2/v2.0/token\", tenantID)\n\n\tdata := url.Values{}\n\tdata.Set(\"client_id\", clientID)\n\tdata.Set(\"client_secret\", clientSecret)\n\tdata.Set(\"scope\", scope)\n\tdata.Set(\"grant_type\", \"client_credentials\")\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, tokenURL, strings.NewReader(data.Encode()))\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed to construct token request\")\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\n\tresp, err := c.Do(req)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed to request token\")\n\t}\n\tdefer resp.Body.Close()\n\n\tb, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed to read token response\")\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, errors.Errorf(\"token request failed (status %d): %s\", resp.StatusCode, string(b))\n\t}\n","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/webhook/teams/app.go#L82-L118","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the wrapped error for the url.Parse failure message identifying the bad URL","Verify the configured token endpoint is a full absolute https:// URL (default: https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token)","Fix the Teams app configuration in Bytebase settings","Restart/resend the webhook so getTokenCached builds a fresh request"],"exampleFix":"// before\n// tokenURL configured as \"login.microsoftonline.com/<tenant>/oauth2/v2.0/token\" (no scheme)\n// after\n// tokenURL configured as \"https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(tokenURL)\nif err != nil || u.Scheme != \"https\" || u.Host == \"\" {\n\treturn fmt.Errorf(\"invalid token URL: %q\", tokenURL)\n}","typeGuard":null,"tryCatchPattern":"// Go: check the wrapped url.Parse error to identify the malformed URL\nif _, err := url.Parse(cfg.TokenURL); err != nil {\n\treturn errors.Wrapf(err, \"invalid teams token url %q\", cfg.TokenURL)\n}","preventionTips":["Store full absolute https:// token endpoint URLs in config","Validate configured URLs at startup, not at request time","Escape templated config values before URL interpolation"],"tags":["teams","oauth","http","url"],"backgroundTag":"invalid-url","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}