Skip to content

Bug: Error handler not catching zodError #61

@rtrampox

Description

@rtrampox

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.

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