{"record":{"id":"dfbc157cfe3ce740","repo":"Tencent/WeKnora","slug":"oauth-token-response-did-not-contain-an-access-tok","errorCode":null,"errorMessage":"OAuth token response did not contain an access_token","messagePattern":"OAuth token response did not contain an access_token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/oauth_tokenstore.go","lineNumber":88,"sourceCode":"\t}\n\tif row == nil || row.AccessToken == \"\" {\n\t\treturn nil, transport.ErrNoToken\n\t}\n\treturn &transport.Token{\n\t\tAccessToken:  row.AccessToken,\n\t\tRefreshToken: row.RefreshToken,\n\t\tTokenType:    row.TokenType,\n\t\tExpiresAt:    row.ExpiresAt,\n\t}, nil\n}\n\n// SaveToken persists a freshly issued or refreshed token.\nfunc (s *dbTokenStore) SaveToken(ctx context.Context, token *transport.Token) error {\n\tif err := ctx.Err(); err != nil {\n\t\treturn err\n\t}\n\tif token == nil || token.AccessToken == \"\" {\n\t\treturn fmt.Errorf(\"OAuth token response did not contain an access_token\")\n\t}\n\tif token.TokenType == \"\" {\n\t\ttoken.TokenType = \"Bearer\"\n\t}\n\texpiresAt := token.ExpiresAt\n\tif expiresAt.IsZero() && token.ExpiresIn > 0 {\n\t\texpiresAt = time.Now().Add(time.Duration(token.ExpiresIn) * time.Second)\n\t}\n\tprincipal := s.principal.Normalize()\n\treturn s.repo.SaveTokenForPrincipal(ctx, &types.MCPOAuthToken{\n\t\tTenantID:      s.tenantID,\n\t\tPrincipalType: principal.Type,\n\t\tPrincipalID:   principal.ID,\n\t\tUserID:        principal.StorageID(),\n\t\tServiceID:     s.serviceID,\n\t\tAccessToken:   token.AccessToken,\n\t\tRefreshToken:  token.RefreshToken,\n\t\tTokenType:     token.TokenType,","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/oauth_tokenstore.go#L70-L106","documentation":"SaveToken persists a transport.Token but refuses to store a nil token or one with an empty AccessToken — such a token is unusable for authenticated requests. This error indicates the OAuth token endpoint response was malformed or the exchange produced no access token.","triggerScenarios":"SaveToken called with a nil *transport.Token, or with a token whose AccessToken field is empty (provider returned error/JSON without access_token, or the token struct was constructed without the access token).","commonSituations":"OAuth provider returned 4xx with a JSON body the transport parsed into an empty token; wrong token endpoint or client credentials caused an error response; provider uses a nonstandard field name for the access token; network proxy stripped the response body.","solutions":["Inspect the token exchange response before SaveToken: log (redacted) status code and body to see whether the provider returned an error like invalid_grant.","Verify client_id/client_secret, redirect_uri, and authorization code are correct and the code was not already consumed (codes are single-use).","Check your provider's token response field name matches what transport.Token parsing expects (access_token).","Never call SaveToken after a failed exchange — gate it on a successful, non-empty exchange result."],"exampleFix":"// before\ntok, _ := exchange(ctx, code)\nstore.SaveToken(ctx, tok)\n// after\ntok, err := exchange(ctx, code)\nif err != nil { return fmt.Errorf(\"token exchange failed: %w\", err) }\nif tok == nil || tok.AccessToken == \"\" {\n    return fmt.Errorf(\"exchange returned no access token; check provider error response\")\n}\nreturn store.SaveToken(ctx, tok)","handlingStrategy":"validation","validationCode":"if token == nil || token.AccessToken == \"\" {\n    return fmt.Errorf(\"refusing to save token: exchange returned no access_token\")\n}","typeGuard":"func hasAccessToken(t *transport.Token) bool {\n    return t != nil && t.AccessToken != \"\"\n}","tryCatchPattern":"if err := store.SaveToken(ctx, token); err != nil {\n    if strings.Contains(err.Error(), \"did not contain an access_token\") {\n        return fmt.Errorf(\"token exchange failed; verify provider credentials and error response: %w\", err)\n    }\n    return err\n}","preventionTips":["Check the exchange error before constructing/saving a token.","Log provider error bodies (redacted) on exchange failure to spot invalid_grant/invalid_client.","Validate redirect_uri and code single-use semantics against your provider.","Confirm the provider's token response field name (access_token) matches your transport's parser."],"tags":["oauth","token","validation","token-exchange"],"backgroundTag":"oauth-access-token-missing","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}