From 08093ab6abc926d386cebac366141d888fd63e8e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 11:58:51 +0000 Subject: [PATCH] fix(cdk): improve OAuth error messages in DeclarativeOauth2Authenticator Remove internal class name 'OAuthAuthenticator' from user-facing error messages and warnings. Replace vague language with specific, actionable descriptions following the writing-good-error-messages guidelines. Changes: - get_client_secret(): Replace warning with clear description that client_secret resolved to empty value - get_client_id(): Replace error with descriptive message about empty client_id resolution - get_token_refresh_endpoint(): Replace error with descriptive message about empty endpoint resolution - __post_init__(): Replace validation errors to remove class name leakage Co-Authored-By: bot_apk --- airbyte_cdk/sources/declarative/auth/oauth.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/airbyte_cdk/sources/declarative/auth/oauth.py b/airbyte_cdk/sources/declarative/auth/oauth.py index e1ad84e09..c7ea5ae37 100644 --- a/airbyte_cdk/sources/declarative/auth/oauth.py +++ b/airbyte_cdk/sources/declarative/auth/oauth.py @@ -175,16 +175,16 @@ def __post_init__(self, parameters: Mapping[str, Any]) -> None: client_creds is None for client_creds in [self.client_id, self.client_secret] ): raise ValueError( - "OAuthAuthenticator configuration error: Both 'client_id' and 'client_secret' are required for the " - "basic OAuth flow." + "OAuth configuration is missing required credentials. Both 'client_id' and 'client_secret' are required for the " + "standard OAuth flow." ) if self.profile_assertion is None and self.use_profile_assertion: raise ValueError( - "OAuthAuthenticator configuration error: 'profile_assertion' is required when using the profile assertion flow." + "OAuth configuration is incomplete. A 'profile_assertion' is required for the profile assertion flow." ) if self.get_grant_type() == "refresh_token" and self._refresh_token is None: raise ValueError( - "OAuthAuthenticator configuration error: A 'refresh_token' is required when the 'grant_type' is set to 'refresh_token'." + "OAuth configuration is missing a required field. A 'refresh_token' is required when 'grant_type' is set to 'refresh_token'." ) def get_token_refresh_endpoint(self) -> Optional[str]: @@ -192,7 +192,7 @@ def get_token_refresh_endpoint(self) -> Optional[str]: refresh_token_endpoint: str = self._token_refresh_endpoint.eval(self.config) if not refresh_token_endpoint: raise ValueError( - "OAuthAuthenticator was unable to evaluate token_refresh_endpoint parameter" + "OAuth token refresh endpoint resolved to an empty value. Verify the 'token_refresh_endpoint' in your connector configuration." ) return refresh_token_endpoint return None @@ -203,7 +203,9 @@ def get_client_id_name(self) -> str: def get_client_id(self) -> str: client_id = self._client_id.eval(self.config) if self._client_id else self._client_id if not client_id: - raise ValueError("OAuthAuthenticator was unable to evaluate client_id parameter") + raise ValueError( + "OAuth client_id resolved to an empty value. Verify the 'client_id' in your connector configuration." + ) return client_id # type: ignore # value will be returned as a string, or an error will be raised def get_client_secret_name(self) -> str: @@ -214,9 +216,10 @@ def get_client_secret(self) -> str: self._client_secret.eval(self.config) if self._client_secret else self._client_secret ) if not client_secret: - # We've seen some APIs allowing empty client_secret so we will only log here + # Some APIs legitimately allow empty client_secret (e.g. public client OAuth flows), + # so we log a warning rather than raising an error. logger.warning( - "OAuthAuthenticator was unable to evaluate client_secret parameter hence it'll be empty" + "OAuth client_secret resolved to an empty value. If this is unexpected, verify the 'client_secret' in your connector configuration." ) return client_secret # type: ignore # value will be returned as a string, which might be empty