Skip to content

FastifyInstance.server returns a number — blocks ws/http2 upgrade piggybacking #1113

Closed

Description

@proggeramlug

Repro (8 lines)

```ts
import Fastify from "fastify";
const app = Fastify({ logger: false });
await app.listen({ host: "127.0.0.1", port: 18099 });
console.log("typeof app.server:", typeof app.server);
console.log("typeof app.server.on:", typeof (app.server as any)?.on);
app.server.on("upgrade", () => {});
```

Observed (perry 0.5.1009)

```
typeof app.server: number
typeof app.server.on: undefined
upgrade handler threw: (number).on is not a function
```

Expected (tsx)

```
typeof app.server: object
typeof app.server.on: function
registered upgrade handler OK
```

Per Fastify docs, `app.server` is the underlying `http.Server` (or `http2.Http2Server`) — `http.Server extends EventEmitter`, so `.on("upgrade" | "connection" | ...)` is supposed to work.

How this blocks WebSocket on Fastify

The canonical way to attach `ws` (or any WS lib) to a Fastify server without opening a second port is:

```ts
import { WebSocketServer } from "ws";
const wss = new WebSocketServer({ noServer: true });
app.server.on("upgrade", (req, socket, head) => {
wss.handleUpgrade(req, socket, head, (sock) => { ... });
});
```

That's exactly what shop-admin's `server/realtime/server.ts` does. With `app.server` being a number, the `.on` call throws at boot, the boot `catch` logs `fatal:`, the process exits. No WebSocket transport possible until `app.server` exposes the real EventEmitter handle.

Pointer

perry's fastify binding presumably has a `js_fastify_app_server` getter or similar that returns the server handle as a tagged-pointer u64 — but the runtime tag/dispatch is treating it as a number on the JS side. Either the FFI return shape needs to be NaN-boxed as an object, or codegen for the `.on` method on this handle needs to route to `js_fastify_server_on` (or equivalent) instead of generic JS `.on` dispatch.

For comparison, `reply.code(X)` was fixed in #1048 — `reply` exposed methods via codegen routing rather than property access on a returned handle. Same pattern needed for `app.server`.

Local checkout: perry 0.5.1009, no edits. Discovered while standing up envelope encryption with the #1075 AES fix landed.

Activity

  1. added 7 commits that reference this issue on May 19, 2026
  2. added 2 commits that reference this issue on Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions