# Node.js 22 Upgrade Guide

Homey Apps now run in a Node.js v22 environment (Homey v12.9.0+), upgraded from Node.js v16 and v18 ([Learn more](https://apps.developer.homey.app/upgrade-guides/pages/-MWdHNw4mqB6t3ogwvDa#node.js)). While Node.js updates are generally backwards compatible, some issues may arise. Below are the currently known issues and solutions listed.

## Known issues

### HTTP(S) calls failing due to "socket hang up"/"ECONNRESET" when using node-fetch

Node.js 19 introduced changes to the management of keep-alive sockets. When using node-fetch, this might cause an `ECONNRESET` error under certain circumstances, particularly with services that aggressively close idle connections:

```javascript
FetchError: request to <> failed, reason: socket hang up
    at ClientRequest.<anonymous> (file:///app/node_modules/node-fetch/src/index.js:109:11)
    at ClientRequest.emit (node:events:519:28)
    at emitErrorEvent (node:_http_client:105:11)
    at Socket.socketOnEnd (node:_http_client:542:5)
    at Socket.emit (node:events:531:35)
    at endReadableNT (node:internal/streams/readable:1698:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
  type: 'system',
  errno: 'ECONNRESET',
  code: 'ECONNRESET',
  erroredSysCall: undefined
}
```

For more information see this GitHub [issue](https://github.com/node-fetch/node-fetch/issues/1735).

#### Solution 1: Use a custom HTTP Agent (recommended for node-fetch)

Provide a custom `http.Agent` or `https.Agent` instance to your node-fetch requests. This ensures proper keep-alive socket management:

```javascript
const fetch = require("node-fetch");
const http = require("http");
const https = require("https");

// Create an agent with keep-alive enabled
const httpAgent = new http.Agent({ keepAlive: true });
const httpsAgent = new https.Agent({ keepAlive: true });

// Use the appropriate agent for your request
fetch("https://example.com/api", {
  agent: (_parsedURL) =>
    _parsedURL.protocol === "http:" ? httpAgent : httpsAgent,
});
```

#### Solution 2: Switch to built-in fetch (recommended for new code)

Node.js 18+ includes a native `fetch()` implementation that handles socket management automatically:

```javascript
// No imports needed, fetch is globally available
const response = await fetch("https://example.com/api");
const data = await response.json();
```

The built-in `fetch` is the preferred approach for new code as it's maintained as part of Node.js and doesn't require external dependencies.

### Missing Host header causing 400 Bad Request

As of Node.js 20, the default HTTP server started requiring a `Host` header to be present on incoming requests. If it is not present it will respond with a 400 Bad Request.

#### Solution

Either add the `Host` header to the requests, or disable the requirement on the server-side:

```javascript
http.createServer({ requireHostHeader: false });
```

For more information see this GitHub [pull request](https://github.com/athombv/com.athom.homeyduino/pull/60).

### Maximum call stack size exceeded when using node-homey-api

Due to socket.io using native Node.js sockets which as of Node.js 22 behave somewhat different, the following error can be observed when node-homey-api tries to close the socket connection:

```
Maximum call stack size exceeded {"stack":"RangeError: Maximum call stack size exceeded\n    at emitInitScript (node:internal/async_hooks:495:24)\n    at process.nextTick (node:internal/process/task_queues:143:5)\n    at emitUncaughtException (node:internal/event_target:1090:11)\n    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:824:9)\n    at WebSocket.dispatchEvent (node:internal/event_target:751:26)\n    at fireEvent (node:internal/deps/undici/undici:11340:14)\n    at failWebsocketConnection (node:internal/deps/undici/undici:11421:9)\n    at closeWebSocketConnection (node:internal/deps/undici/undici:11692:9)\n    at WebSocket.close (node:internal/deps/undici/undici:12352:9)\n    at WS.doClose (file:///../node_modules/engine.io-client/build/esm-debug/transports/websocket.js:83:21)"}
```

**Solution:**

Update node-homey-api to version 3.14.17 or newer.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://apps.developer.homey.app/upgrade-guides/node-22.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
