Skip to content

AOT compilation removes beforeHandle when using arrow function expression #1617

@sparten11740

Description

@sparten11740

What version of Elysia is running?

Tested on 1.4.13, 1.4.18

What platform is your computer?

Darwin 24.6.0 arm64 arm

What environment are you using

Tested on Node v22.16.0, v24.2.0

Are you using dynamic mode?

no

What steps can reproduce the bug?

  1. Create the below files
  2. npm install
  3. npm test
  4. the test using the arrow function expression fails, the test using the arrow function with a block as body passes
package.json
{
  "name": "elysia-bug-repro",
  "type": "module",
  "scripts": {
    "test": "node --test --test-force-exit --import tsx index.test.ts"
  },
  "dependencies": {
    "@elysiajs/node": "1.4.2",
    "@types/node": "22.19.2",
    "tsx": "4.21.0",
    "elysia": "1.4.18"
  }
}
tsconfig.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Default",
  "compilerOptions": {
    "lib": ["ES2024"],
    "target": "ES2022"
  },
  "exclude": ["node_modules"]
}
index.test.ts
import { test, describe } from 'node:test'
import assert from 'node:assert/strict'
import { Elysia, status } from 'elysia'
import node from '@elysiajs/node'

type HandlerParams = { status: typeof status };

const requireSignature =
	(
		secret: string,
		{
			message
		}: { message: string },
	) =>
		async ({ status }: HandlerParams) => {
                         // just a dummy implementation always returning 401, we're doing HMAC in our app
			return status(401, 'Invalid signature');
		};

const app = new Elysia({
	prefix: '/users/:id',
	adapter: node()
}).post('/', async () => 'Hello World', {
	beforeHandle: async ({params, status}) => requireSignature('my secret', {
			message: params.id
		})({status})
})

const appBlock = new Elysia({
	prefix: '/users/:id',
	adapter: node()
}).post('/', async () => 'Hello World', {
	beforeHandle: async ({params, status}) => {
		return requireSignature('my secret', {
			message: params.id
		})({status})
	}
})


describe('beforeHandle AOT incorrect pruning repro', () => {
	test('arrow function expression returns 401', async () => {
		const request = new Request('http://localhost/users/abc', {method: 'POST'})
		const response = await app.handle(request)
		assert.equal(response.status, 401)
	})

	test('arrow function block returns 401', async () => {
		const request = new Request('http://localhost/users/abc', {method: 'POST'})
		const response = await appBlock.handle(request)
		assert.equal(response.status, 401)
	})
})

What is the expected behavior?

Both tests should pass, AOT compilation should not remove beforeHandle. This can lead to severe security vulnerabilities

What do you see instead?

Screen.Recording.2025-12-11.at.16.24.10.mov

Additional information

I faced another flavor of this bug which was even more severe because everything worked as expected in our unit tests with app.handle but stopped working in the actual app when requesting via http and in integration tests fired against the app via http after using app.listen

Have you try removing the node_modules and bun.lockb and try again yet?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions