Skip to content

Handle specific exceptions in HTTPClientInterceptor with detailed res…#2945

Draft
predic8 wants to merge 2 commits into
masterfrom
network-error-messages
Draft

Handle specific exceptions in HTTPClientInterceptor with detailed res…#2945
predic8 wants to merge 2 commits into
masterfrom
network-error-messages

Conversation

@predic8
Copy link
Copy Markdown
Member

@predic8 predic8 commented May 14, 2026

…ponses

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced error handling for backend server connectivity issues with more descriptive error messages
    • Improved handling of socket exceptions and connection timeouts
    • More informative HTTP error responses for gateway connectivity and timeout scenarios

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

📝 Walkthrough

Walkthrough

HTTPClientInterceptor is updated to use explicit imports instead of wildcards and to refine exception handling in the handleRequest method. Connection failures (ConnectException, SocketException, EOFWhileReadingLineException) are now handled with dedicated catch blocks returning 502 responses, while socket timeouts return 504 responses with improved response construction.

Changes

HTTPClientInterceptor robustness improvement

Layer / File(s) Summary
Import consolidation
core/src/main/java/com/predic8/membrane/core/interceptor/HTTPClientInterceptor.java
Wildcard and grouped imports are replaced with explicit import and import static statements for annotations, exchange/proxy/HTTP utilities, logging types, and interceptor outcome/flow constants.
Exception handling refinement
core/src/main/java/com/predic8/membrane/core/interceptor/HTTPClientInterceptor.java
ConnectException handling is refactored; SocketException and EOFWhileReadingLineException are given dedicated 502 "Bad Gateway" handlers with distinct subSee values; SocketTimeoutException is changed to log via log.info and return 504 "Gateway Timeout" response with socket-timeout detail, omitting prior destination-specific detail text.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • membrane/api-gateway#2885: Both PRs modify HTTPClientInterceptor.handleRequest's exception-handling logic to expand specific backend/tunneling failure response paths (including UnableToTunnelException in #2885 and SocketException/EOFWhileReadingLineException handlers in this PR).

Suggested reviewers

  • rrayst

Poem

🐰 Explicit imports, crystal clear,
No more wildcards cluttering here,
Socket faults now mapped just right,
502s and 504s taking flight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: handling specific exceptions in HTTPClientInterceptor with detailed responses, which matches the file changes and PR objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch network-error-messages

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@core/src/main/java/com/predic8/membrane/core/interceptor/HTTPClientInterceptor.java`:
- Around line 123-127: The 504 response builder call
(internal(router.getConfiguration().isProduction(),
getDisplayName()).title("Gateway
Timeout").status(504).addSubSee("socket-timeout").buildAndSetResponse(exc)) is
missing a .detail(...) message; update that chain to include a concise timeout
detail (e.g., explain that the backend did not respond within the socket timeout
and suggest retrying or checking upstream) so clients receive actionable
information—modify the builder invocation in HTTPClientInterceptor to call
.detail(...) before buildAndSetResponse(exc).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 505c2723-b31c-4e05-8f2d-e03dd5d49854

📥 Commits

Reviewing files that changed from the base of the PR and between bc4a0e8 and 6b59373.

📒 Files selected for processing (1)
  • core/src/main/java/com/predic8/membrane/core/interceptor/HTTPClientInterceptor.java

Comment on lines 123 to 127
internal(router.getConfiguration().isProduction(), getDisplayName())
.title("Gateway Timeout")
.status(504)
.addSubSee("socket-timeout")
.detail("Target %s is not reachable.".formatted(exc.getDestinations()))
.buildAndSetResponse(exc);
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot May 14, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add timeout detail text to the 504 response.

Line 123–127 currently omits .detail(...), which makes timeout failures less actionable for clients than the other new handlers.

Suggested patch
         } catch (SocketTimeoutException e) {
             // Details are logged further down in the HTTPClient
             log.info("Target {} is not reachable.",exc.getDestinations());
             internal(router.getConfiguration().isProduction(), getDisplayName())
                     .title("Gateway Timeout")
                     .status(504)
                     .addSubSee("socket-timeout")
+                    .detail("Timed out while waiting for a response from target %s.".formatted(exc.getDestinations()))
                     .buildAndSetResponse(exc);
             return ABORT;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
internal(router.getConfiguration().isProduction(), getDisplayName())
.title("Gateway Timeout")
.status(504)
.addSubSee("socket-timeout")
.detail("Target %s is not reachable.".formatted(exc.getDestinations()))
.buildAndSetResponse(exc);
internal(router.getConfiguration().isProduction(), getDisplayName())
.title("Gateway Timeout")
.status(504)
.addSubSee("socket-timeout")
.detail("Timed out while waiting for a response from target %s.".formatted(exc.getDestinations()))
.buildAndSetResponse(exc);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/HTTPClientInterceptor.java`
around lines 123 - 127, The 504 response builder call
(internal(router.getConfiguration().isProduction(),
getDisplayName()).title("Gateway
Timeout").status(504).addSubSee("socket-timeout").buildAndSetResponse(exc)) is
missing a .detail(...) message; update that chain to include a concise timeout
detail (e.g., explain that the backend did not respond within the socket timeout
and suggest retrying or checking upstream) so clients receive actionable
information—modify the builder invocation in HTTPClientInterceptor to call
.detail(...) before buildAndSetResponse(exc).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@coderabbitai should we really reveal the backend addresses to the client?

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.

@predic8 That's a valid security concern — exposing backend addresses leaks internal network topology to potentially untrusted clients, which is generally undesirable in production environments.

I also notice that the PR deliberately removed the previous .detail("Target %s is not reachable.".formatted(exc.getDestinations())) from the SocketTimeoutException handler, which suggests this was likely intentional.

There are two reasonable paths:

  1. Keep no detail (current state) — clients get a 504 Gateway Timeout with the socket-timeout subtype, which is actionable enough without revealing internals. The log.info(...) already captures the destination server-side.

  2. Use a generic, address-free message — if a detail is still desired for client usability:

         } catch (SocketTimeoutException e) {
             log.info("Target {} is not reachable.", exc.getDestinations());
             internal(router.getConfiguration().isProduction(), getDisplayName())
                     .title("Gateway Timeout")
                     .status(504)
                     .addSubSee("socket-timeout")
+                    .detail("The backend did not respond within the timeout period.")
                     .buildAndSetResponse(exc);
             return ABORT;

It may also be worth reviewing the SocketException handler at line 107–112, which does include exc.getDestinations() in its detail — the same concern applies there.


✏️ Learnings added
Learnt from: predic8
Repo: membrane/api-gateway PR: 2945
File: core/src/main/java/com/predic8/membrane/core/interceptor/HTTPClientInterceptor.java:123-127
Timestamp: 2026-05-14T08:54:25.466Z
Learning: In membrane/api-gateway (HTTPClientInterceptor.java), the PR owner (predic8) considers it a security concern to expose backend addresses (exc.getDestinations()) in HTTP error response detail messages, as it leaks internal network topology to clients. Prefer generic messages (e.g., "The backend did not respond within the timeout period.") over destination-formatted strings in ProblemDetails `.detail(...)` calls.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: rrayst
Repo: membrane/api-gateway PR: 2863
File: core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java:107-107
Timestamp: 2026-03-11T21:11:47.936Z
Learning: When reviewing refactors that extract logic from a synchronized block into a new method, verify that the synchronization guard (the GuardedBy target, e.g., the lock on paths) is carried into the extracted method and not dropped. Ensure shared fields annotated with GuardedBy(

@membrane-ci-server
Copy link
Copy Markdown

This pull request needs "/ok-to-test" from an authorized committer.

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.

1 participant