Skip to content

Conversation

@zdql
Copy link
Contributor

@zdql zdql commented Nov 21, 2025

No description provided.

@railway-app
Copy link

railway-app bot commented Nov 21, 2025

🚅 Deployed to the echo-pr-695 environment in echo

Service Status Web Updated (UTC)
echo ◻️ Removed (View Logs) Web Nov 21, 2025 at 2:59 pm

@vercel
Copy link
Contributor

vercel bot commented Nov 21, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
assistant-ui-template Ready Ready Preview Comment Nov 21, 2025 1:39am
echo-control (staging) Ready Ready Preview Comment Nov 21, 2025 1:39am
echo-next-boilerplate Ready Ready Preview Comment Nov 21, 2025 1:39am
echo-next-image Ready Ready Preview Comment Nov 21, 2025 1:39am
echo-next-sdk-example Ready Ready Preview Comment Nov 21, 2025 1:39am
echo-video-template Ready Ready Preview Comment Nov 21, 2025 1:39am
echo-vite-sdk-example Ready Ready Preview Comment Nov 21, 2025 1:39am
next-chat-template Ready Ready Preview Comment Nov 21, 2025 1:39am
react-boilerplate Ready Ready Preview Comment Nov 21, 2025 1:39am
react-chat Ready Ready Preview Comment Nov 21, 2025 1:39am
react-image Ready Ready Preview Comment Nov 21, 2025 1:39am
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
component-registry Skipped Skipped Nov 21, 2025 1:39am

@railway-app railway-app bot temporarily deployed to echo (echo / echo-pr-695) November 21, 2025 01:40 Destroyed
}

// Case 2: Settle failed but model succeeded
if (!settleResult && modelResult.success) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Case 2 (settle failed but model succeeded) calls handleResolveResponse after settle has already sent a 402 response, which will cause an Express error when trying to send a second response to the same request.

View Details
📝 Patch Details
diff --git a/packages/app/server/src/handlers.ts b/packages/app/server/src/handlers.ts
index 131d35d9..fb53c578 100644
--- a/packages/app/server/src/handlers.ts
+++ b/packages/app/server/src/handlers.ts
@@ -54,11 +54,7 @@ export async function handleX402Request({
       provider: provider.getType(),
       url: req.url,
     });
-    modelRequestService.handleResolveResponse(
-      res,
-      isStream,
-      data
-    );
+    // Note: settle already sent a 402 response, so we should not attempt to send another response
     return;
   }
 

Analysis

Double response error in handleX402Request Case 2

What fails: In handleX402Request() (packages/app/server/src/handlers.ts, lines 46-62), when settle fails but the model request succeeds (Case 2), the code calls modelRequestService.handleResolveResponse() after settle has already sent a 402 response via buildX402Response(), causing Express to throw "Error: Can't set headers after they are sent to the client".

How to reproduce:

  1. Send an X402 request where payment settlement fails (e.g., invalid payment authorization)
  2. Simultaneously, the model request succeeds
  3. The settle handler calls buildX402Response(req, res, maxCost) which sends res.status(402).json(resBody)
  4. Case 2 then attempts to call modelRequestService.handleResolveResponse(res, isStream, data) which calls either res.json(data) (non-streaming) or res.end() (streaming)
  5. Express throws error because headers were already sent

Result: Error thrown and logged by error handler: "Error: Can't set headers after they are sent to the client". While the 402 response reaches the client (and the error handler checks res.headersSent before attempting another response), this is incorrect behavior - no error should be thrown since the 402 response is the correct outcome.

Expected: When settle fails and sends a 402 response indicating payment is required, no subsequent response should be attempted. The 402 response should be the final response to the client.

Root cause: Express.js specification requires exactly one response per HTTP request. Once response headers are sent, attempting to set additional headers or send another response violates this protocol and throws an error.

@zdql zdql merged commit 3573142 into production Nov 21, 2025
17 of 19 checks passed
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