jstack
jstack copied to clipboard
Bug: Error handler not catching zodError
When there's a validation error on the input schema, the error thrown by zod is not catched, and instead an Internal Server Error is shown.
src/server/jstack.ts:
import { jstack } from "jstack";
import { db } from "./db";
import { getCurrentSession } from "./sessions";
import { HTTPException } from "hono/http-exception";
interface Env {}
export const j = jstack.init<Env>();
/**
* Type-safely injects database into all procedures
* @see https://jstack.app/docs/backend/middleware
*
* For deployment to Cloudflare Workers
* @see https://developers.cloudflare.com/workers/tutorials/postgres/
*/
const databaseMiddleware = j.middleware(async ({ next }) => {
return await next({ db });
});
/**
* Middleware to check if the current session is valid
* @see https://jstack.app/docs/backend/middleware
*/
const authMiddleware = j.middleware(async ({ next, c }) => {
const session = await getCurrentSession(c);
if (!session) {
throw new HTTPException(401, { message: "Unauthorized" });
}
return await next({ session });
});
/**
* Public (unauthenticated) procedures
*/
export const publicProcedure = j.procedure.use(databaseMiddleware);
/**
* Protected (authenticated) procedures
*/
export const protectedProcedure = j.procedure.use(databaseMiddleware).use(authMiddleware);
src/server/index.ts:
import { j } from "./jstack";
import { authRouter } from "./routers/auth-router";
/**
* This is your base API.
* Here, you can handle errors, not-found responses, cors and more.
*
* @see https://jstack.app/docs/backend/app-router
*/
const api = j.router().basePath("/api").use(j.defaults.cors).onError(j.defaults.errorHandler);
/**
* This is the main router for your server.
* All routers in /server/routers should be added here manually.
*/
const appRouter = j.mergeRouters(api, {
auth: authRouter,
});
export type AppRouter = typeof appRouter;
export default appRouter;
src/server/routers/auth-router.ts:
export const authRouter = j.router({
emailExists: publicProcedure.input(emailExistsSchema).post(async ({ c, input, ctx }) => {
const { email } = input;
const { db } = ctx;
const userQuery = await db.select({ email: Users.email }).from(Users).where(eq(Users.email, email));
const user = userQuery.pop();
return c.json({ exists: !!user });
}),
})
This request returns Internal Server Error.
curl -X POST http://localhost:5173/api/auth/emailExists -H "Content-Type: application/json" -d "{}"
and in the console, the zodError gets logged:
POST /api/auth/emailExists 500 in 168ms
[Error [ZodError]: [
{
"code": "invalid_type",
"expected": "object",
"received": "undefined",
"path": [],
"message": "Required"
}
]] {
issues: [Array],
addIssue: [Function (anonymous)],
addIssues: [Function (anonymous)]
}
ps: While testing, I've seen that errors related to the JSON input also returns Internal Server Error.