Error Handling

Error Handling

Error Formatting

Added in v5.2

You can customize the server-side behavior in your API handler's options by using an error formatter.

By default, the client only receives a generic message like "Failed to run middleware" to avoid leaking any sensitive information. You can customize this behavior by specifying the errorFormatter option when you initialize your file route helper. An error formatter runs on the server and takes the original UploadThingError, and returns a JSON-serializable object. The error also includes a cause property which contains more information about the nature of the error and what caused the error to throw in the first place.

You can also throw an UploadThingError inside your middleware which will send the error message to the client. All other error types will use a generic error message. Regardless of what error is thrown, you can still change the defaults with errorFormatter.

server/uploadthing.ts
import { createUploadthing, type FileRouter } from "uploadthing/next";
import { UploadThingError } from "uploadthing/server";
 
const f = createUploadthing();
 
const auth = (req: Request) => ({ id: "fakeId" });
 
export const ourFileRouter = {
  imageUploader: f({ image: { maxFileSize: "4MB" } })
    .middleware(async ({ req }) => {
      const user = await auth(req);
 
      if (!user) throw new Error(`Cant find user from req: ${req.toString()}`); // client onError will get "Failed to run middleware"
      if (!user.id) throw new UploadThingError("No user ID"); // client onError will get "No user ID"
 
      return { userId: user.id };
    })
    .onUploadComplete(async ({ metadata, file }) => {
      console.log("Upload complete for userId:", metadata.userId);
 
      console.log("file url", file.url);
 
      return { uploadedBy: metadata.userId };
    }),
} satisfies FileRouter;
 
export type OurFileRouter = typeof ourFileRouter;

UploadThingError

For most users, throwing an UploadThingError("your message") will be enough. For advanced use cases, you can pass an options object for more control.

type UploadThingErrorOptions<T> =
  | {
      /**
   * ERROR_CODES:
   *  BAD_REQUEST: 400,
   *  NOT_FOUND: 404,
   *  FORBIDDEN: 403,
   *  INTERNAL_SERVER_ERROR: 500,
   *  INTERNAL_CLIENT_ERROR: 500,
      
   *  // S3 specific
   *  TOO_LARGE: 413,
   *  TOO_SMALL: 400,
   *  TOO_MANY_FILES: 400,
   *  KEY_TOO_LONG: 400,
      
   *  // UploadThing specific
   *  URL_GENERATION_FAILED: 500,
   *  UPLOAD_FAILED: 500,
   *  MISSING_ENV: 500,
   *  FILE_LIMIT_EXCEEDED: 500,
   * @default `INTERNAL_SERVER_ERROR`
   */
      code?: keyof typeof ERROR_CODES;
      /**
       * Your error message describing what happened
       * @default `An unknown error occurred`
       */
      message?: string;
      /**
       * The original error that caused this, if any.
       */
      cause?: unkown;
      /**
       * Data associated with the error
       */
      data?: T;
    }
  | string;

If you're using Zod as an input parser, you can return information of what fields failed validation by checking if the cause is a ZodError. Zod provides a flatten method that returns a JSON-serializable object which we can return to the client.

server/uploadthing.ts
import * as z from "zod";
 
import { createUploadthing } from "uploadthing/next";
import type { FileRouter } from "uploadthing/next";
 
const f = createUploadthing({
  errorFormatter: (err) => {
    return {
      message: err.message,
      zodError: err.cause instanceof z.ZodError ? err.cause.flatten() : null,
    };
  },
});
 
export const uploadRouter = {
  withInput: f(["image"]).input(z.object({ foo: z.string() })),
  //  ...
} satisfies FileRouter;

Catching errors on the client

You can catch errors on the client by using the onUploadError property on the premade components, or the useUploadthing hook. You can access the JSON object that you returned from your error formatter on the data property:

<UploadButton
  endpoint="withInput"
  input={{ foo: userInput }}
  onUploadError={(error) => {
    console.log("Error: ", error);
    const fieldErrors = error.data?.zodError?.fieldErrors;
    //                              ^? typeToFlattenedError
    setError(fieldErrors.foo[0] ?? "");
  }}
/>