Problem
I am deploying a Bun + Elysia API to Vercel. The build succeeds, but every request returns a 500: FUNCTION_INVOCATION_FAILED error. Locally, the application runs perfectly with bun run src/server.ts.
Current Behavior
When accessing the deployment, the function crashes immediately:
Error: FUNCTION_INVOCATION_FAILED
Runtime Logs:
ResolveMessage {} Bun process exited with exit status: 1.
The logs above can help with debugging the issue.
Note
This is similar to a previous topic I created, but I am now using Bun and Elysia as my backend with path aliases and React for four routes.
Previous topic: Vercel Bun runtime crashes..
What I’ve Tried
- Confirmed entry point is a default export with no
.listen()call. - Verified the app runs perfectly locally using
bun dev. vercel.jsonmatches the officialElysiaVercel template.- Attempted troubleshooting with AI (ChatGPT/Claude), but suggested solutions did not resolve the crash.
Questions
- How can I extract the actual crash error or stack trace from Vercel’s
Bunruntime? - Are there known incompatibilities with using path aliases and
Reactin a backendBunElysiaserverless environment?
Environment
- Framework:
Elysia^1.4.22 - Runtime:
Bun1.x(viavercel.json) - Plugins:
@elysiajs/cors,@elysiajs/static,@elysiajs/openapi - Entry point:
src/index.ts(default export ofElysiaapp)
Configuration
package.json
{
"name": "****",
"version": "0.0.0",
"scripts": {
"dev": "bun --hot src/server.ts",
"build": "echo 'Build skipped: Bun runs TS/TSX directly'",
"lint": "eslint . --cache --cache-location .eslintcache",
"db:test": "bun scripts/db-select-test.ts",
"token:getexpat": "bun scripts/get-token-expiry.ts"
},
"dependencies": {
"@elysiajs/cors": "^1.4.1",
"@elysiajs/jwt": "^1.4.0",
"@elysiajs/openapi": "^1.4.14",
"@elysiajs/static": "^1.4.7",
"elysia": "^1.4.22",
"lucide-react": "^0.564.0",
"mssql": "^12.2.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"ws": "^8.19.0",
"zod": "^4.3.5"
},
"devDependencies": {
"@types/bun": "1.3.1",
"@types/mssql": "^9.1.8",
"@types/react": "^19.2.9",
"@types/react-dom": "^19.2.3",
"@types/ws": "^8.18.1",
"typescript": "5.8.3"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"rootDir": "./src",
"jsx": "react-jsx",
"jsxImportSource": "react",
"strict": true,
"skipLibCheck": true,
"allowImportingTsExtensions": false,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@@/*": ["./*"]
}
},
"include": ["src"],
"exclude": ["node_modules"]
}
vercel.json
{
"bunVersion": "1.x"
}
Source Code
src/index.ts
import { ALLOWED_ORIGINS } from "@/lib/constants";
import { MyError, errors } from "@/lib/errors";
import { serverGate } from "@/middleware/server-gate";
import aboutRouter from "@/routes/about";
import healthzRouter from "@/routes/healthz";
import homeRouter from "@/routes/home";
import loginRouter from "@/routes/login";
import v1Router from "@/routes/v1/v1.router";
import { cors } from "@elysiajs/cors";
import { openapi } from "@elysiajs/openapi";
import { staticPlugin } from "@elysiajs/static";
import { Elysia } from "elysia";
import { ZodError } from "zod";
const app = new Elysia()
.error({
MyError,
})
.use(
openapi({
path: "/openapi",
documentation: {
info: {
title: "API",
version: "v1"
}
}
})
)
.onError(({ error, status, code }) => {
// Error handling logic
});
app.use(cors({ /* ... */ }));
app.use(staticPlugin({ assets: "public", prefix: "/" }));
app.use(loginRouter);
app.use(homeRouter);
app.use(aboutRouter);
app.use(healthzRouter);
app.use(v1Router);
export default app;
src/routes/login.ts
import { Login } from "@/components/Login";
import { getAzureSQLDbPool } from "@/lib/db";
import { loginSchema } from "@/schemas/login";
import { Elysia } from "elysia";
import React from "react";
import { renderToReadableStream } from "react-dom/server.browser";
import z from "zod";
const router = new Elysia({ prefix: "/login" })
router.get("", async () => {
const html = React.createElement(Login, { title: `Login | Record log API` });
const stream = await renderToReadableStream(html);
return new Response(stream, {
headers: { "Content-Type": "text/html" }
});
});
export default router;
src/components/Login.tsx
import { Lock, User } from "lucide-react";
type Props = {
title: string;
};
export function Login({ title }: Props): React.ReactElement {
return (
<html lang="en">
<head>
<meta charSet="UTF-8" />
<title>{title}</title>
</head>
<body>
<div className="login-container">
<form method="POST">
<input name="username" placeholder="Username" required />
<input name="password" type="password" placeholder="Password" required />
<button type="submit">Sign In</button>
</form>
</div>
</body>
</html>
);
}