Repository navigation
Using hono-node with the cors middleware causes a memory leak #269
Description
What version of Hono are you using?
4.8.12
What runtime/platform is your app running on? (with version if possible)
Node
What steps can reproduce the bug?
Clone this repo
https://github.com/krzkz94/hono-context-memory-leak
Follow the outlined steps
(install, run app, run autocannon)
Notice heap size increasing
npx tsx src/index.ts
Server is running on http://localhost:3000
{ before: '9.09', after: '9.09' }
{ before: '9.11', after: '9.11' }
{ before: '51.49', after: '51.50' }
{ before: '67.14', after: '67.14' }
{ before: '111.91', after: '111.91' }
{ before: '155.77', after: '155.77' }
{ before: '126.81', after: '126.81' }
{ before: '162.79', after: '162.79' }
{ before: '207.94', after: '207.94' }
{ before: '254.23', after: '254.23' }
{ before: '302.14', after: '302.14' }
{ before: '342.52', after: '342.52' }
{ before: '380.52', after: '380.52' }
{ before: '248.96', after: '248.96' }
{ before: '288.23', after: '288.23' }
{ before: '339.07', after: '339.07' }
{ before: '382.03', after: '382.03' }
{ before: '424.34', after: '424.34' }
{ before: '458.85', after: '458.85' }
{ before: '511.55', after: '511.55' }
{ before: '552.79', after: '552.79' }
{ before: '596.38', after: '596.38' }
{ before: '590.64', after: '590.64' }
Node22
What is the expected behavior?
Heap size stays consistent with minimal increases, for example, below, it's the result without the cors middleware.
tsx watch src/index.ts
Server is running on http://localhost:3000
{ before: '17.41', after: '17.41' }
{ before: '11.33', after: '11.33' }
{ before: '10.58', after: '10.58' }
{ before: '23.65', after: '23.65' }
{ before: '14.78', after: '14.78' }
{ before: '17.13', after: '17.13' }
{ before: '16.21', after: '16.21' }
{ before: '16.23', after: '16.23' }
{ before: '13.44', after: '13.45' }
{ before: '14.90', after: '14.90' }
{ before: '21.29', after: '21.29' }
{ before: '18.71', after: '18.71' }
{ before: '14.91', after: '14.91' }
{ before: '13.46', after: '13.46' }
What do you see instead?
Heap size increases and stays high even after the test ends
{ before: '8.94', after: '8.94' }
{ before: '8.96', after: '8.96' }
{ before: '30.07', after: '30.07' }
{ before: '77.18', after: '77.18' }
{ before: '87.71', after: '87.71' }
{ before: '131.37', after: '131.37' }
{ before: '164.34', after: '164.34' }
{ before: '206.36', after: '206.36' }
{ before: '157.07', after: '157.07' }
{ before: '189.13', after: '189.13' }
{ before: '232.51', after: '232.51' }
{ before: '280.68', after: '280.68' }
{ before: '328.30', after: '328.30' }
{ before: '366.00', after: '366.00' }
{ before: '410.61', after: '410.61' }
{ before: '461.95', after: '461.95' }
{ before: '491.38', after: '491.38' }
{ before: '314.48', after: '314.48' }
{ before: '363.24', after: '363.24' }
{ before: '412.60', after: '412.60' }
{ before: '451.58', after: '451.58' }
{ before: '492.87', after: '492.87' }
{ before: '509.95', after: '509.95' } <- end of test
{ before: '509.95', after: '509.95' }
{ before: '509.96', after: '509.96' }
{ before: '509.96', after: '509.96' }
{ before: '509.97', after: '509.97' }
{ before: '509.97', after: '509.97' }
{ before: '509.97', after: '509.98' }
{ before: '509.98', after: '509.98' }
{ before: '509.99', after: '509.99' }
{ before: '509.99', after: '509.99' }
{ before: '509.99', after: '510.00' }
Additional information
It seems a bug with node-server and how things are handled when accessing the headers, running this with Bun's native HTTP server, doesn't cause issues. (bun --expose-gc src/index.ts) - also, removing the serve() wrapper around the object and just exporting default.
Basically accessing c.req.header('origin') (or any header for the matter), builds memory pressure, and under constant load, keeps increasing the memory requirement without ever giving it a chance to be cleaned up until either (a) the load stops or (b) the application runs out of memory
Activity
[-]Using hono-context with the cors middleware causes a memory leak[/-][+]Using hono-node with the cors middleware causes a memory leak[/+]omarkhatibgg commentedon Aug 5, 2025
I'm facing the same issue, my server is crashing every 10 mins.
yusukebe commentedon Aug 5, 2025
@omarkhatibco
I'll work on investigating it. One question, are you running your app on Node.js? or other runtime?
omarkhatibgg commentedon Aug 5, 2025
Hey @yusukebe ,
It's a simple node.js server with 1 endpoint.
you can see in the image the memory leak, it starts to happens yesterday when I merged my PR which includes latest version of Hono v4.8.12
The workaround what to disable cors plugin and just use normal headers in the response.
yusukebe commentedon Aug 5, 2025
@omarkhatibco
Does this mean the previous version you used did not cause a memory leak? Let me know the previous version.
krzkz94 commentedon Aug 5, 2025
@yusukebe I upgraded from 4.7.9 as I experienced the issue there and it did not go away with 4.8.12 - mind you, I had some other issues in my app with memory management and managed to fix all of them except this one so I don't want to lead you the wrong way by saying that it was there already in 4.7.9
yusukebe commentedon Aug 5, 2025
@krzkz94 Okay, thanks!
yusukebe commentedon Aug 5, 2025
@krzkz94
What version of
@hono/node-serverdo you use?omarkhatibgg commentedon Aug 5, 2025
Hey @yusukebe
I just noticed that the issue start to appear on 25th on July, I couldn't test which one, but I think that last one I had no problem with was
4.8.5and@hono/node-serverwas on1.17.0you can see the image below
krzkz94 commentedon Aug 5, 2025
@yusukebe Should've mentioned it, my bad
"@hono/node-server": "1.18.1",
"hono": "4.8.12"
yusukebe commentedon Aug 5, 2025
@omarkhatibco @krzkz94 Thanks!
yusukebe commentedon Aug 5, 2025
This is a bug in
@hono/node-server. You can reproduce it with the following code withouthono. Should be fixed. I'll transfer this issue to thehonojs/node-serverrepository.yusukebe commentedon Aug 5, 2025
Hi @usualoma
Sorry for again and again.
This memory leak is caused by introducing a lightweight request in the Node.js Adapter. As proof, the problem does not occur with version
1.2.3before1.3.0that includes the lightweight request feature.Here is the minimal repro: https://github.com/yusukebe/hono-nodejs-adapter-memory-leak
Can you investigate it?
usualoma commentedon Aug 5, 2025
I'll check. Please wait a moment.
usualoma commentedon Aug 5, 2025
The same problem that was fixed below is occurring.
#172
Changing the following will prevent memory leaks.
usualoma commentedon Aug 6, 2025
Based on my investigation, I have come to the following conclusion. There is room for adjustment, but I do not believe this is a memory leak in node-server.
global.gcTo use this, you need to specify the
--expose-gcoption.If you make the following changes, you should be able to confirm that memory usage does not continue to increase.
Improvements when using
corsmiddlewareIn the following comment, it was mentioned that simply using
corscaused a fallback to the originalglobalThis.Request, which triggered the problem. Therefore, in the case ofcors(or rather, simple access to the header), it may be better to optimize node-server further.#266 (comment)
krzkz94 commentedon Aug 6, 2025
Hi @usualoma, we've created a patch with the changes outlined here
Basically, renaming the signal variable (I assume so it can't be referenced somewhere else) has solved our issue with the memory leak when using the cors middleware. Memory is released even under pressure and returns to expected levels even over longer periods of time (hours)
Attached the patch below for anyone who might wanna try it out to see if it fixes their issue (s)
@hono%2Fnode-server@1.18.1.patch
tgdn commentedon Aug 29, 2025
Any updates?
usualoma commentedon Oct 19, 2025
Within the scope I verified, explicitly executing
global.gc()seemed to free the memory.I created a PR that explicitly executes
global.gc()every N times when the--expose-gcandrequestsPerForcedGCoptions are specified. Could someone verify if this resolves the issue?#283
krzkz94 commentedon Oct 21, 2025
@usualoma the memory logger here https://github.com/krzkz94/hono-context-memory-leak/blob/main/src/index.ts#L8 does run global.gc (not every n request, but on a per-second basis), but if memory pressure is high (constant flow of requests, production system) gc never runs until it runs out of memory.
Accessing headers seems to cause this problem, eventually the memory will drop, but never to baseline (where it started), with the patch you suggested (patching signal/abordController), it works perfectly, and we have been running it in production currently with no issues over the last 3+ months
usualoma commentedon Oct 21, 2025
Hi @krzkz94, thanks for your reply!
Just to confirm:
As shown in #269 (comment), the
--expose-gcflag is required to executeglobal.gc(). Did you run it with this flag? (It wasn't specified in the repository you shared.)Based on my local tests, when the
--expose-gcflag is specified, GC appears to be executed.usualoma commentedon Oct 21, 2025
I think there's also a way to do it optionally like this,
Before that, I want to verify operation in an environment where I can reproduce the memory leak (unrecovered even after GC runs).
usualoma commentedon Nov 2, 2025
Hmm, after digging into this for a while, I don’t think this is an actual memory leak.
Because of how Undici is implemented, the AbortController objects tend to get promoted into the old generation, so unless you explicitly call global.gc(), they’re not collected (or at least not collected quickly).
https://github.com/nodejs/undici/blob/92715645444a41d3d6b3be0a458630cf32150adf/lib/web/fetch/request.js#L33-L35
What I found is that we can actually work around this by setting --max-old-space-size, like this:
usualoma commentedon Nov 2, 2025
As a practical workaround for this, I suppose it would be feasible to enable something equivalent via an option. However, I still consider this merely a symptomatic solution, so I'm rather torn about whether it should be implemented.
+ _signal: abortController.signal, // Do not pass signalkrzkz94 commentedon Nov 2, 2025
Yes, --expose-gc was passed as well as global.gc() is called
https://github.com/krzkz94/hono-context-memory-leak/blob/main/src/index.ts#L8
File was executed with bun --expose-gc src/index.ts
339sasaki commentedon Feb 11, 2026
@yusukebe hi, #269 FYI
I didn't face the issue when I tried Later Hono v4.8.12, following.
Hono@4.11.9
Node v24.13.1
src/indes.ts > node index.ts
Server is running on http://localhost:3000
{ before: '12.92', after: '12.93' }
{ before: '12.94', after: '12.94' }
|
{ before: '13.01', after: '13.01' }
{ before: '13.03', after: '13.03' }
{ before: '10.89', after: '10.90' }
{ before: '10.92', after: '10.92' }
|
{ before: '11.00', after: '11.00' }
I tried above on my local environment this afternoon as I talk about with you.
Thank you for local Hack event to try today.