Skip to content

fix: flag authentication issues as config errors#69279

Merged
Maxime Carbonneau-Leclerc (maxi297) merged 2 commits into
masterfrom
maxi297/fix_google_analytics_auth
Nov 12, 2025
Merged

fix: flag authentication issues as config errors#69279
Maxime Carbonneau-Leclerc (maxi297) merged 2 commits into
masterfrom
maxi297/fix_google_analytics_auth

Conversation

@maxi297
Copy link
Copy Markdown
Contributor

@maxi297 Maxime Carbonneau-Leclerc (maxi297) commented Nov 11, 2025

What

Addresses https://airbyte.pagerduty.com/incidents/Q0MU1CM2NJU6WY

Following airbytehq/airbyte-python-cdk#829

How

Update CDK version

Given invalid oauth creds, we have:

% docker run -v $(pwd)/secrets:/secrets airbyte/source-google-analytics-data-api:2.9.15 read --config /secrets/config.json --catalog /secrets/catalog.json
...
{"type":"TRACE","trace":{"type":"ERROR","emitted_at":1762872254263,"error":{"message":"Something went wrong in the connector. See the logs for more details.","internal_message":"400 Client Error: Bad Request for url: https://www.googleapis.com/oauth2/v4/token","stack_trace":"Traceback (most recent call last):\n  File \"/airbyte/integration_code/main.py\", line 4, in <module>\n    run()\n    ~~~^^\n  File \"/airbyte/integration_code/source_declarative_manifest/run.py\", line 307, in run\n    handle_command(args)\n    ~~~~~~~~~~~~~~^^^^^^\n  File \"/airbyte/integration_code/source_declarative_manifest/run.py\", line 91, in handle_command\n    handle_local_manifest_command(args)\n    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^\n  File \"/airbyte/integration_code/source_declarative_manifest/run.py\", line 129, in handle_local_manifest_command\n    launch(\n    ~~~~~~^\n        source=source,\n        ^^^^^^^^^^^^^^\n        args=args,\n        ^^^^^^^^^^\n    )\n    ^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/entrypoint.py\", line 377, in launch\n    for message in source_entrypoint.run(parsed_args):\n                   ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/entrypoint.py\", line 207, in run\n    yield from map(\n    ...<2 lines>...\n    )\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/entrypoint.py\", line 280, in read\n    for message in self.source.read(self.logger, config, catalog, state):\n                   ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/concurrent_declarative_source.py\", line 381, in read\n    yield from self._concurrent_source.read(selected_concurrent_streams)\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/concurrent_source/concurrent_source.py\", line 123, in read\n    yield from self._submit_initial_partition_generators(concurrent_stream_processor)\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/concurrent_source/concurrent_source.py\", line 137, in _submit_initial_partition_generators\n    status_message = concurrent_stream_processor.start_next_partition_generator()\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py\", line 197, in start_next_partition_generator\n    stream.as_airbyte_stream(),\n    ~~~~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/concurrent/default_stream.py\", line 61, in as_airbyte_stream\n    json_schema=dict(self.get_json_schema()),\n                     ~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/concurrent/default_stream.py\", line 56, in get_json_schema\n    return self._json_schema() if callable(self._json_schema) else self._json_schema\n           ~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/schema/caching_schema_loader_decorator.py\", line 13, in get_json_schema\n    self._loaded_schema = self._decorated.get_json_schema()\n                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/schema/dynamic_schema_loader.py\", line 137, in get_json_schema\n    retrieved_record = next(self.retriever.read_records({}), None)  # type: ignore[call-overload] # read_records return Iterable data type\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py\", line 544, in read_records\n    for stream_data in self._read_pages(record_generator, self.state, _slice):\n                       ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py\", line 428, in _read_pages\n    response = self._fetch_next_page(stream_state, stream_slice, next_page_token)\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py\", line 338, in _fetch_next_page\n    return self.requester.send_request(\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^\n        path=self._paginator_path(\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^\n    ...<27 lines>...\n        log_formatter=self.log_formatter,\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n    )\n    ^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/requesters/http_requester.py\", line 467, in send_request\n    headers=self._request_headers(\n            ~~~~~~~~~~~~~~~~~~~~~^\n        stream_state, stream_slice, next_page_token, request_headers\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n    ),\n    ^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/requesters/http_requester.py\", line 315, in _request_headers\n    headers = self._get_request_options(\n        stream_state,\n    ...<4 lines>...\n        extra_headers,\n    )\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/requesters/http_requester.py\", line 298, in _get_request_options\n    auth_options_method(),\n    ~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 85, in get_auth_header\n    token = self.access_token if self._is_access_token_flow else self.get_access_token()\n                                                                 ~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 91, in get_access_token\n    token, expires_in = self.refresh_access_token()\n                        ~~~~~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 139, in refresh_access_token\n    response_json = self._make_handled_request()\n  File \"/usr/local/lib/python3.13/site-packages/backoff/_sync.py\", line 105, in retry\n    ret = target(*args, **kwargs)\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 224, in _make_handled_request\n    response.raise_for_status()\n    ~~~~~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/requests/models.py\", line 1026, in raise_for_status\n    raise HTTPError(http_error_msg, response=self)\nrequests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://www.googleapis.com/oauth2/v4/token\n","failure_type":"system_error"}}}

With the new version:

% docker run -v $(pwd)/secrets:/secrets airbyte/source-google-analytics-data-api:dev read --config /secrets/config.json --catalog /secrets/catalog.json
...
{"type":"TRACE","trace":{"type":"ERROR","emitted_at":1762872222814,"error":{"message":"Refresh token is invalid or expired. Please re-authenticate from Sources/<your source>/Settings.","internal_message":"Refresh token is invalid or expired. Please re-authenticate from Sources/<your source>/Settings.","stack_trace":"Traceback (most recent call last):\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 224, in _make_handled_request\n    response.raise_for_status()\n    ~~~~~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/requests/models.py\", line 1026, in raise_for_status\n    raise HTTPError(http_error_msg, response=self)\nrequests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://www.googleapis.com/oauth2/v4/token\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/airbyte/integration_code/main.py\", line 4, in <module>\n    run()\n    ~~~^^\n  File \"/airbyte/integration_code/source_declarative_manifest/run.py\", line 307, in run\n    handle_command(args)\n    ~~~~~~~~~~~~~~^^^^^^\n  File \"/airbyte/integration_code/source_declarative_manifest/run.py\", line 91, in handle_command\n    handle_local_manifest_command(args)\n    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^\n  File \"/airbyte/integration_code/source_declarative_manifest/run.py\", line 129, in handle_local_manifest_command\n    launch(\n    ~~~~~~^\n        source=source,\n        ^^^^^^^^^^^^^^\n        args=args,\n        ^^^^^^^^^^\n    )\n    ^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/entrypoint.py\", line 377, in launch\n    for message in source_entrypoint.run(parsed_args):\n                   ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/entrypoint.py\", line 207, in run\n    yield from map(\n    ...<2 lines>...\n    )\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/entrypoint.py\", line 280, in read\n    for message in self.source.read(self.logger, config, catalog, state):\n                   ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/concurrent_declarative_source.py\", line 381, in read\n    yield from self._concurrent_source.read(selected_concurrent_streams)\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/concurrent_source/concurrent_source.py\", line 123, in read\n    yield from self._submit_initial_partition_generators(concurrent_stream_processor)\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/concurrent_source/concurrent_source.py\", line 137, in _submit_initial_partition_generators\n    status_message = concurrent_stream_processor.start_next_partition_generator()\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py\", line 197, in start_next_partition_generator\n    stream.as_airbyte_stream(),\n    ~~~~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/concurrent/default_stream.py\", line 61, in as_airbyte_stream\n    json_schema=dict(self.get_json_schema()),\n                     ~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/concurrent/default_stream.py\", line 56, in get_json_schema\n    return self._json_schema() if callable(self._json_schema) else self._json_schema\n           ~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/schema/caching_schema_loader_decorator.py\", line 13, in get_json_schema\n    self._loaded_schema = self._decorated.get_json_schema()\n                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/schema/dynamic_schema_loader.py\", line 137, in get_json_schema\n    retrieved_record = next(self.retriever.read_records({}), None)  # type: ignore[call-overload] # read_records return Iterable data type\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py\", line 544, in read_records\n    for stream_data in self._read_pages(record_generator, self.state, _slice):\n                       ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py\", line 428, in _read_pages\n    response = self._fetch_next_page(stream_state, stream_slice, next_page_token)\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/retrievers/simple_retriever.py\", line 338, in _fetch_next_page\n    return self.requester.send_request(\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^\n        path=self._paginator_path(\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^\n    ...<27 lines>...\n        log_formatter=self.log_formatter,\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n    )\n    ^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/requesters/http_requester.py\", line 467, in send_request\n    headers=self._request_headers(\n            ~~~~~~~~~~~~~~~~~~~~~^\n        stream_state, stream_slice, next_page_token, request_headers\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n    ),\n    ^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/requesters/http_requester.py\", line 315, in _request_headers\n    headers = self._get_request_options(\n        stream_state,\n    ...<4 lines>...\n        extra_headers,\n    )\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/declarative/requesters/http_requester.py\", line 298, in _get_request_options\n    auth_options_method(),\n    ~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 85, in get_auth_header\n    token = self.access_token if self._is_access_token_flow else self.get_access_token()\n                                                                 ~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 91, in get_access_token\n    token, expires_in = self.refresh_access_token()\n                        ~~~~~~~~~~~~~~~~~~~~~~~~~^^\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 139, in refresh_access_token\n    response_json = self._make_handled_request()\n  File \"/usr/local/lib/python3.13/site-packages/backoff/_sync.py\", line 105, in retry\n    ret = target(*args, **kwargs)\n  File \"/usr/local/lib/python3.13/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py\", line 250, in _make_handled_request\n    raise AirbyteTracedException(\n        internal_message=message, message=message, failure_type=FailureType.config_error\n    )\nairbyte_cdk.utils.traced_exception.AirbyteTracedException: Refresh token is invalid or expired. Please re-authenticate from Sources/<your source>/Settings.\n","failure_type":"config_error"}}}

Review guide

User Impact

Can this PR be safely reverted and rolled back?

  • YES 💚
  • NO ❌

@github-actions
Copy link
Copy Markdown
Contributor

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

Helpful Resources

PR Slash Commands

Airbyte Maintainers (that's you!) can execute the following slash commands on your PR:

  • /format-fix - Fixes most formatting issues.
  • /bump-version - Bumps connector versions.
    • You can specify a custom changelog by passing changelog. Example: /bump-version changelog="My cool update"
    • Leaving the changelog arg blank will auto-populate the changelog from the PR title.
  • /run-cat-tests - Runs legacy CAT tests (Connector Acceptance Tests)
  • /build-connector-images - Builds and publishes a pre-release docker image for the modified connector(s).
  • JVM connectors:
    • /update-connector-cdk-version connector=<CONNECTOR_NAME> - Updates the specified connector to the latest CDK version.
      Example: /update-connector-cdk-version connector=destination-bigquery
    • /bump-bulk-cdk-version bump=patch changelog='foo' - Bump the Bulk CDK's version. bump can be major/minor/patch.
  • Python connectors:
    • /poe connector source-example lock - Run the Poe lock task on the source-example connector, committing the results back to the branch.
    • /poe source example lock - Alias for /poe connector source-example lock.
    • /poe source example use-cdk-branch my/branch - Pin the source-example CDK reference to the branch name specified.
    • /poe source example use-cdk-latest - Update the source-example CDK dependency to the latest available version.

📝 Edit this welcome message.


| Version | Date | Pull Request | Subject |
|:---------------|:-----------|:---------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 2.9.16 | 2025-11-11 | [69278](https://github.com/airbytehq/airbyte/pull/69278) | Flag authentication issues as config_error |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [vale] reported by reviewdog 🐶
[Vale.Spelling] Did you really mean 'config_error'?


| Version | Date | Pull Request | Subject |
|:---------------|:-----------|:---------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 2.9.16 | 2025-11-11 | [69279](https://github.com/airbytehq/airbyte/pull/69279) | Flag authentication issues as config_error |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [vale] reported by reviewdog 🐶
[Vale.Spelling] Did you really mean 'config_error'?

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Nov 11, 2025

source-google-analytics-data-api Connector Test Results

14 tests   11 ✅  9s ⏱️
 2 suites   3 💤
 2 files     0 ❌

Results for commit af73c6a.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Nov 11, 2025

Deploy preview for airbyte-docs ready!

✅ Preview
https://airbyte-docs-nakuxju4n-airbyte-growth.vercel.app

Built with commit 3debbb6.
This pull request is being automatically deployed with vercel-action

@maxi297 Maxime Carbonneau-Leclerc (maxi297) merged commit beacc20 into master Nov 12, 2025
37 checks passed
@maxi297 Maxime Carbonneau-Leclerc (maxi297) deleted the maxi297/fix_google_analytics_auth branch November 12, 2025 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants