Skip to content

fix(cdk): improve HTTP 400 default error message and reclassify as config_error#963

Draft
devin-ai-integration[bot] wants to merge 3 commits intomainfrom
devin/1774534061-fix-400-error-message
Draft

fix(cdk): improve HTTP 400 default error message and reclassify as config_error#963
devin-ai-integration[bot] wants to merge 3 commits intomainfrom
devin/1774534061-fix-400-error-message

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot commented Mar 26, 2026

Summary

The CDK's default error mapping for HTTP 400 responses previously used a generic static message ("HTTP Status Code: 400. Error: Bad request. Please check your request parameters.") and classified errors as system_error. This swallowed the actual API response body, making 400 errors nearly impossible to diagnose without checking logs.

Two changes:

  1. FailureType reclassification: HTTP 400 changed from system_errorconfig_error. HTTP 400 typically indicates a client-side issue (bad config, invalid parameters, insufficient permissions). Since 400 was already mapped to ResponseAction.FAIL (not RETRY), this does not change retry behavior — it only changes how the error is categorized in the platform.

  2. Dynamic user-facing message: When no custom error_message is set in the ErrorResolution (i.e., the default mapping), the user-facing message now includes the parsed API response body: "API responded with HTTP 400: {parsed_error}". Connectors that provide their own error_message via custom error handlers are unaffected — their message is used as-is.

The verbose internal details (request body, response headers, full response body) remain in internal_message for debugging.

Resolves https://github.com/airbytehq/airbyte-internal-issues/issues/16112
Related to https://github.com/airbytehq/oncall/issues/11791

Updates since last revision

  • Updated test_default_error_handler.py to align test expectations with the new HTTP 400 defaults: FailureType.config_error and error_message=None. The test for _with_http_response_status_400_fail_with_default_failure_type was asserting the old system_error and static message string.
  • Updated test_resumable_full_refresh.py: test_resumable_full_refresh_failure now expects FailureType.config_error and asserts "400" appears in the error message (previously asserted system_error and "Bad request").

Review & Testing Checklist for Human

  • Validate FailureType reclassification impact: HTTP 400 is now config_error instead of system_error. Confirm this is the desired platform behavior — it affects error categorization in the UI and oncall routing. It does NOT affect retries (400 is FAIL, not RETRY).
  • No direct unit tests for the new dynamic message branches: The user_facing_message construction in http_client.py has 3 branches (custom message / parsed API error / bare status code). Existing tests all provide explicit error_message values in their ErrorResolution, so only the first branch is covered. The None error_message paths (parsed body fallback and bare status code fallback) are not directly tested. Consider adding targeted tests.
  • Edge case: non-parseable response body: When parse_response_error_message() returns None (e.g., binary response, empty body), the fallback is "API responded with HTTP 400." — verify this is acceptable vs. the old static message.
  • Test with a real connector: Run a declarative connector against an API that returns a 400 with a JSON error body to verify the parsed error appears in the user-facing message.

Notes

  • The filter_secrets call on the dynamic user-facing message only filters known Airbyte secrets, not arbitrary sensitive data from API responses. This is a pre-existing limitation, not introduced by this PR.
  • CDK uses poetry-dynamic-versioning — no manual version bump needed.
  • test_http_client.py tests for HTTP 400 with FailureType.system_error were not changed because those tests supply custom error_mapping overrides rather than relying on DEFAULT_ERROR_MAPPING.

Link to Devin session: https://app.devin.ai/sessions/8f84207400894451b1b68deb627dd017

…nfig_error

- Change FailureType for HTTP 400 from system_error to config_error
- Surface parsed API response body in user-facing error message when
  no custom error_message is set in the ErrorResolution
- Keep verbose details in internal_message for debugging

Resolves airbytehq/airbyte-internal-issues#16112

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 and CI 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/1774534061-fix-400-error-message#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/1774534061-fix-400-error-message

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

github-actions bot commented Mar 26, 2026

PyTest Results (Fast)

3 934 tests  ±0   3 923 ✅ ±0   7m 31s ⏱️ +32s
    1 suites ±0      11 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit 4555bd5. ± Comparison against base commit acafc75.

This pull request removes 1 and adds 1 tests. Note that renamed tests count towards both.
unit_tests.sources.declarative.requesters.error_handlers.test_default_error_handler ‑ test_default_error_handler_with_custom_response_filter[_with_http_response_status_400_fail_with_default_failure_type-400-test_response_filter0-ResponseAction.RETRY-FailureType.system_error-HTTP Status Code: 400. Error: Bad request. Please check your request parameters.]
unit_tests.sources.declarative.requesters.error_handlers.test_default_error_handler ‑ test_default_error_handler_with_custom_response_filter[_with_http_response_status_400_fail_with_default_failure_type-400-test_response_filter0-ResponseAction.RETRY-FailureType.config_error-None]

♻️ This comment has been updated with latest results.

devin-ai-integration bot and others added 2 commits March 26, 2026 14:23
…age changes

Co-Authored-By: bot_apk <apk@cognition.ai>
…lassification

Co-Authored-By: bot_apk <apk@cognition.ai>
@github-actions
Copy link
Copy Markdown

PyTest Results (Full)

3 937 tests  ±0   3 925 ✅ ±0   10m 41s ⏱️ -8s
    1 suites ±0      12 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit 4555bd5. ± Comparison against base commit acafc75.

This pull request removes 1 and adds 1 tests. Note that renamed tests count towards both.
unit_tests.sources.declarative.requesters.error_handlers.test_default_error_handler ‑ test_default_error_handler_with_custom_response_filter[_with_http_response_status_400_fail_with_default_failure_type-400-test_response_filter0-ResponseAction.RETRY-FailureType.system_error-HTTP Status Code: 400. Error: Bad request. Please check your request parameters.]
unit_tests.sources.declarative.requesters.error_handlers.test_default_error_handler ‑ test_default_error_handler_with_custom_response_filter[_with_http_response_status_400_fail_with_default_failure_type-400-test_response_filter0-ResponseAction.RETRY-FailureType.config_error-None]

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants