(edited)
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> );}