pingdotgg / uploadthing

File uploads for modern web devs
https://uploadthing.com
MIT License
4.27k stars 319 forks source link

UploadThing Callback Failing on Localhost with useUploadThing Hook #1032

Closed wilsuriel03 closed 1 month ago

wilsuriel03 commented 1 month ago

I understand that this issue may be closed if it should be filed in another category

My issue

I'm experiencing an issue where UploadThing successfully uploads images, but the callback to my local application fails. As a result, uploaded images are not being reflected in my application's UI. The callback error indicates a transport issue when attempting to POST to http://localhost:3000/api/uploadthing.

Error Logs:

✓ Compiled /api/uploadthing in 1068ms (3228 modules)
POST /api/uploadthing?actionType=upload&slug=productUploader 200 in 1175ms
ERROR (#42) handleJsonLineStream=2033ms handleUploadAction=2064ms: Failed to forward callback request from dev stream
  signature: hmac-sha256=40a14c33081b1e4975a1dc6000812132343411241341409966217ac8f85d2284b351d
  hook: callback
  payload: {"status":"uploaded","metadata":{},"file":{"url":"https://utfs.io/f/BSckEMHO6XG2adfasdfasfasdfafdafdafas4","appUrl":"https://utfs.io/a/valy6o7o4x/BScadfasfafasdfXG23OekOJasdfafasfsafG9Ilotg865bzk4","name":"fwfwff33f.png","key":"BSckEMHO6XG23OekOJzETPZOjfUwcvhVyLG9Ilotg865bzk4","size":2493007,"type":"image/png","customId":null,"fileHash":"f9460ef834258c9be42a7675124523522304b"}}
  error: RequestError: Transport error (POST http://localhost:3000/api/uploadthing)
    at fetch failed: TypeError: Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer```

Environment:

UploadThing Version: @uploadthing/react@^7.0.3
Node Version: 20.16
Framework: Next.js

Relevant Code Snippets:

1. app/api/uploadthing/core.ts:

import type { FileRouter } from "uploadthing/next";
import { createUploadthing } from "uploadthing/next";

const f = createUploadthing();

// FileRouter for your app, can contain multiple FileRoutes
export const ourFileRouter = {
  productUploader: f({ image: { maxFileSize: "4MB" } }).onUploadComplete(
    async ({ metadata, file }) => {
      // Handle upload completion
      console.log("Upload complete:", file);
      // Add logic to save the file URL to your database or update state
    },
  ),
} satisfies FileRouter;

export type OurFileRouter = typeof ourFileRouter;

2. app/api/uploadthing/route.ts:


import { createRouteHandler } from "uploadthing/next";
import { ourFileRouter } from "./core";

// Export routes for Next App Router
export const { GET, POST } = createRouteHandler({
  router: ourFileRouter,
});

3. app/_components/upload.tsx:

import {
  generateUploadButton,
  generateUploadDropzone,
  generateReactHelpers,
} from "@uploadthing/react";

import type { OurFileRouter } from "~/app/api/uploadthing/core";

export const UploadButton = generateUploadButton<OurFileRouter>();
export const UploadDropzone = generateUploadDropzone<OurFileRouter>();
export const { useUploadThing, uploadFiles } = generateReactHelpers<OurFileRouter>();

4. product-images.tsx:

"use client";

import { Control } from "react-hook-form";
import { useFieldArray } from "@ecommerce/ui/form";
import { useDragControls, Reorder, motion } from "@ecommerce/ui/motion";
import { Button } from "@ecommerce/ui/button";
import Icon from "~/app/_components/icon";
import { useUploadThing } from "~/app/_components/upload";

interface ProductImagesProps {
  control: Control<any>;
  productName: string;
}

const MAX_IMAGES = 3;

export default function ProductImages({ control, productName }: ProductImagesProps) {
  const { fields: images, append, remove, move } = useFieldArray({
    control,
    name: "images",
  });

  const { startUpload, isUploading } = useUploadThing("productUploader", {
    onClientUploadComplete: (res) => {
      if (res) {
        res.forEach((uploadedFile) => {
          append({
            url: uploadedFile.url,
            altText: productName,
            isPrimary: images.length === 0,
          });
        });
      }
    },
    onUploadError: (error) => {
      console.error("Upload error:", error);
    },
  });

  const addImage = (event: React.ChangeEvent<HTMLInputElement>) => {
    if (event.target.files) {
      const files = Array.from(event.target.files);
      const remainingSlots = MAX_IMAGES - images.length;
      const filesToUpload = files.slice(0, remainingSlots);

      if (filesToUpload.length > 0) {
        startUpload(filesToUpload);
      }
    }
  };

  return (
    <section>
      {/* UI Elements */}
      <input type="file" multiple accept="image/*" onChange={addImage} />
      {/* Rest of the UI */}
    </section>
  );
}
itsmejawad commented 1 month ago

How did you mange to fix that? I'm having the same issue.

wilsuriel03 commented 1 month ago

I was able to resolve the issue by excluding the /api/uploadthing endpoint from my middleware configuration. It seems the middleware was interfering with the callback request from UploadThing, causing the transport error. By excluding this specific route, the callback was able to complete without issues. If you're experiencing the same problem, check your middleware setup and try excluding the UploadThing API routes

andrerocha commented 2 weeks ago

https://docs.uploadthing.com/faq#my-callback-runs-in-development-but-not-in-production