Conversation
[Feature] settle in parallel
|
🚅 Deployed to the echo-pr-695 environment in echo
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
| } | ||
|
|
||
| // Case 2: Settle failed but model succeeded | ||
| if (!settleResult && modelResult.success) { |
There was a problem hiding this comment.
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:
- Send an X402 request where payment settlement fails (e.g., invalid payment authorization)
- Simultaneously, the model request succeeds
- The settle handler calls
buildX402Response(req, res, maxCost)which sendsres.status(402).json(resBody) - Case 2 then attempts to call
modelRequestService.handleResolveResponse(res, isStream, data)which calls eitherres.json(data)(non-streaming) orres.end()(streaming) - 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.
No description provided.