{"record":{"id":"94c4936c62d86ff5","repo":"Tencent/WeKnora","slug":"authorization-server-returned-an-empty-access-toke","errorCode":null,"errorMessage":"authorization server returned an empty access token","messagePattern":"authorization server returned an empty access token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/oauth_lifecycle.go","lineNumber":223,"sourceCode":"\tif oauthTokenMaterialChanged(current, observed) &&\n\t\t(current.ExpiresAt.IsZero() || current.ExpiresAt.After(time.Now().Add(oauthRefreshSkew))) {\n\t\treturn nil\n\t}\n\tif current.RefreshToken == \"\" {\n\t\treturn r.invalidateToken(ctx, false, \"no refresh token is available\")\n\t}\n\n\thandler := override\n\tif handler == nil {\n\t\thandler = r.handler\n\t}\n\trefreshed, refreshErr := handler.RefreshToken(ctx, current.RefreshToken)\n\tif refreshErr == nil && refreshed != nil && refreshed.AccessToken != \"\" {\n\t\tlogger.GetLogger(ctx).Infof(\"MCP OAuth token refreshed: service=%s principal=%s\", r.serviceID, r.principal.StorageID())\n\t\treturn nil\n\t}\n\tif refreshErr == nil {\n\t\trefreshErr = errors.New(\"authorization server returned an empty access token\")\n\t}\n\tpermanent, resetClient := permanentRefreshFailure(refreshErr)\n\tif permanent {\n\t\treturn r.invalidateToken(ctx, resetClient, \"the refresh token or OAuth client is no longer valid\")\n\t}\n\treturn &OAuthRefreshTemporaryError{Err: refreshErr}\n}\n\nfunc oauthTokenMaterialChanged(current, observed *types.MCPOAuthToken) bool {\n\tif current == nil || observed == nil {\n\t\treturn current != observed\n\t}\n\treturn current.AccessToken != observed.AccessToken ||\n\t\tcurrent.RefreshToken != observed.RefreshToken ||\n\t\t!current.ExpiresAt.Equal(observed.ExpiresAt)\n}\n\nfunc (r *oauthRuntime) invalidateToken(ctx context.Context, resetClient bool, reason string) error {","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/oauth_lifecycle.go#L205-L241","documentation":"Raised inside the MCP OAuth token-refresh path (refreshAsLeaseOwner, invoked via refreshWithLease) when the authorization server's refresh response succeeds but carries an empty access_token. The token material is unusable, so the refresh must be treated as failed and the cached token invalidated.","triggerScenarios":"Thrown at internal/mcp/oauth_lifecycle.go:223 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Retry the refresh; some servers transiently return empty tokens","Force a full re-authorization flow (invalidate token and redirect the user to authorize again)","Check the OAuth server's token endpoint response format and grant configuration","Verify the client's scopes/audience still permit issuing access tokens"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}