Bug
The /v1/images/image2image handler (proxy.ts ~L2698) does not create a clientAbort AbortController, unlike the /v1/images/generations handler (L2498) which correctly cancels upstream requests when the client disconnects.
If a client disconnects mid-request, the upstream call continues and the x402 payment settles the user is charged for a result nobody receives.
Steps to reproduce
Send a request to /v1/images/image2image
Disconnect the client before the upstream response arrives
Observe that the upstream request completes and x402 payment settles despite no client to receive the result
Expected behavior
The upstream request and x402 payment should be cancelled when the client disconnects, matching the behavior of /v1/images/generations.
Suggested fix
Add the same clientAbort pattern already used in the image generation handler:
const clientAbort = new AbortController();
res.on("close", () => {
if (!res.writableEnded) clientAbort.abort();
});
const upstream = await payFetch(${apiBase}/v1/images/image2image, {
method: "POST",
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
body: reqBody,
signal: clientAbort.signal, // ← missing today
});
Bug
The /v1/images/image2image handler (proxy.ts ~L2698) does not create a clientAbort AbortController, unlike the /v1/images/generations handler (L2498) which correctly cancels upstream requests when the client disconnects.
If a client disconnects mid-request, the upstream call continues and the x402 payment settles the user is charged for a result nobody receives.
Steps to reproduce
Send a request to /v1/images/image2image
Disconnect the client before the upstream response arrives
Observe that the upstream request completes and x402 payment settles despite no client to receive the result
Expected behavior
The upstream request and x402 payment should be cancelled when the client disconnects, matching the behavior of /v1/images/generations.
Suggested fix
Add the same clientAbort pattern already used in the image generation handler:
const clientAbort = new AbortController();
res.on("close", () => {
if (!res.writableEnded) clientAbort.abort();
});
const upstream = await payFetch(
${apiBase}/v1/images/image2image, {method: "POST",
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
body: reqBody,
signal: clientAbort.signal, // ← missing today
});