Skip to content

fix(low-code): honor declared failure_type on retry filters and clean up exhaustion message - #1115

Draft
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1786551537-honor-declared-failure-type
Draft

fix(low-code): honor declared failure_type on retry filters and clean up exhaustion message#1115
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1786551537-honor-declared-failure-type

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

Two fixes to what a user sees (and how connector health is classified) when a declarative retry budget is exhausted. Motivated by a source-tiktok-marketing failure that surfaced as:

Exhausted available request attempts. Please see logs for more details. Exception: TikTok Marketing API returned a transient server-side error (code 50000). The connector will retry automatically. System error.

with failureType: system_error.

1. HttpResponseFilter ignored a declared failure_type unless the action was FAIL.

- if self.failure_type and filter_action == ResponseAction.FAIL:
+ if self.failure_type and filter_action in {FAIL, RETRY, RATE_LIMITED, REFRESH_TOKEN_THEN_RETRY}:
      failure_type = self.failure_type
  elif default_mapped_error_resolution: ...
  else: failure_type = FailureType.system_error

APIs that signal errors as HTTP 200 with an in-body error code (TikTok Marketing, among others) have no DEFAULT_ERROR_MAPPING entry for 200, so a RETRY filter always resolved to system_error no matter what the manifest declared. That resolution's failure_type rides on DefaultBackoffException and is reused when retries are exhausted (http_client.py:317-323, propagation added in #762) — so the CDK was already designed to honor a declared failure_type; the declarative filter simply never supplied one for non-FAIL actions.

IGNORE and RESET_PAGINATION deliberately keep the previous default-mapping behavior: IGNORE emits no failure downstream (only a log line), so there is no reason to change its semantics here.

2. The retry-exhaustion message replayed retry-phase narration.

- message=f"Exhausted available request attempts. Please see logs for more details. Exception: {e}",
+ message="Available request retry attempts are exhausted.",

The old string interpolated the retry-phase error_message verbatim, which is how "The connector will retry automatically" ended up in a message emitted after retries were exhausted, and it also carried remediation text. internal_message is unchanged and still contains the full exception detail (including the vendor error text), so nothing is lost for debugging. Follows the writing-good-error-messages guidelines.

Blast radius / breaking-change assessment

This is opt-in: behavior only changes for manifests that already declare a failure_type next to a non-FAIL action. Grepping airbytehq/airbyte, that's 7 connectors today, and all of them declare exactly what they'd now get:

  • source-slack, source-pinterest, source-hubspotRATE_LIMITED/RETRY: transient_error
  • source-intercomRETRY: transient_error (its IGNORE/RESET_PAGINATION declarations are unaffected)
  • source-apple-search-adsREFRESH_TOKEN_THEN_RETRY: transient_error (8 declarations)
  • source-hubspotREFRESH_TOKEN_THEN_RETRY: config_error
  • source-linearRATE_LIMITED: transient_error
  • source-zendesk-support — only IGNORE declarations, unaffected

I don't believe this is a breaking change under the connector breaking-change rules: no spec, schema, state, or stream-scope change, and no records are added or dropped. What changes is the FailureType label and the user-facing message on an already-failing sync — some previously-system_error failures now report as whatever the manifest declares (typically transient_error), which is the intended correction. Downstream consumers that key off the exact old exhaustion string would see a different string; that string was not a documented interface.

Testing

  • HttpResponseFilter: declared failure_type is honored on RETRY; a declared failure_type on IGNORE still resolves from the default mapping (asserts the deliberate carve-out).
  • HttpClient: end-to-end retry exhaustion through a declarative RETRY filter that declares transient_error — asserts the resulting FailureType, the exact user-facing message, and that the retry-phase detail is preserved in internal_message.
  • One existing parametrized case was updated (test_http_response_filter.py): it asserted that a declared config_error on a RETRY filter resolved to the default instead of the declaration. That expectation encoded the bug, so it now asserts the declared value.
  • pytest on the affected files (72 passed) plus the broader declarative error-handler and streams/http suites (559 passed); ruff check, ruff format --check, and mypy clean.

Related to https://github.com/airbytehq/oncall/issues/13291:

A companion PR in airbytehq/airbyte rewords the source-tiktok-marketing retry filter messages and declares failure_type: transient_error on them; the declaration only takes effect once a source-declarative-manifest base image ships this CDK change.

Link to Devin session: https://app.devin.ai/sessions/052578ae518045c88abdfe6311014bc7

devin-ai-integration Bot and others added 2 commits August 12, 2026 16:21
Co-Authored-By: bot_apk <apk@cognition.ai>
Co-Authored-By: bot_apk <apk@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

Testing This CDK Version

You can test this version of the CDK using the following:

# Run the CLI from this branch:
uvx 'git+https://github.com/airbytehq/airbyte-python-cdk.git@devin/1786551537-honor-declared-failure-type#egg=airbyte-python-cdk[dev]' --help

# Update a connector to use the CDK from this branch ref:
cd airbyte-integrations/connectors/source-example
poe use-cdk-branch devin/1786551537-honor-declared-failure-type

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /autofix - Fixes most formatting and linting issues
  • /poetry-lock - Updates poetry.lock file
  • /test - Runs connector tests with the updated CDK
  • /prerelease - Triggers a prerelease publish with default arguments
  • /poe build - Regenerate git-committed build artifacts, such as the pydantic models which are generated from the manifest JSON schema in YAML.
  • /poe <command> - Runs any poe command in the CDK environment
📚 Show Repo Guidance

Helpful Resources

📝 Edit this welcome message.

@github-actions

Copy link
Copy Markdown

PyTest Results (Fast)

4 231 tests  +2   4 219 ✅ +2   8m 15s ⏱️ -9s
    1 suites ±0      12 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit c4686df. ± Comparison against base commit 68bc294.

This pull request removes 1 and adds 3 tests. Note that renamed tests count towards both.
unit_tests.sources.declarative.requesters.error_handlers.test_http_response_filter ‑ test_matches[test_http_code_matches_failure_type_config_error_action_retry_uses_default_failure_type]
unit_tests.sources.declarative.requesters.error_handlers.test_http_response_filter ‑ test_matches[test_http_code_matches_failure_type_config_error_action_retry]
unit_tests.sources.declarative.requesters.error_handlers.test_http_response_filter ‑ test_matches[test_http_code_matches_ignore_action_uses_default_failure_type]
unit_tests.sources.streams.http.test_http_client ‑ test_send_request_exhaustion_preserves_declared_failure_type_and_hides_retry_details

@github-actions

Copy link
Copy Markdown

PyTest Results (Full)

4 234 tests  +2   4 222 ✅ +2   12m 44s ⏱️ -3s
    1 suites ±0      12 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit c4686df. ± Comparison against base commit 68bc294.

This pull request removes 1 and adds 3 tests. Note that renamed tests count towards both.
unit_tests.sources.declarative.requesters.error_handlers.test_http_response_filter ‑ test_matches[test_http_code_matches_failure_type_config_error_action_retry_uses_default_failure_type]
unit_tests.sources.declarative.requesters.error_handlers.test_http_response_filter ‑ test_matches[test_http_code_matches_failure_type_config_error_action_retry]
unit_tests.sources.declarative.requesters.error_handlers.test_http_response_filter ‑ test_matches[test_http_code_matches_ignore_action_uses_default_failure_type]
unit_tests.sources.streams.http.test_http_client ‑ test_send_request_exhaustion_preserves_declared_failure_type_and_hides_retry_details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants