onClientUploadComplete is never called

I am trying to integrate UploadThing into my app. This is also my first time realy using it, but im having a bit of a problem. Im quit confussed on how everything works, and i stuck with this problem. In my Client the onClientUploadComplete never gets called, even when i have a callback URL that sends a 200 status. The file gets Uploaded no problem, but the loading spinner never disapears and the code inside the onClientUploadComplete block also never "fire". Here is some context of my Code: app/api/uploadthing/core.ts
import { auth } from "@clerk/nextjs/server";
import { createUploadthing, type FileRouter } from "uploadthing/next";
import { UploadThingError } from "uploadthing/server";

const f = createUploadthing();

// FileRouter for your app, can contain multiple FileRoutes
export const ourFileRouter = {
// Define as many FileRoutes as you like, each with a unique routeSlug

uploader: f({
image: {
/**
* For full list of options and defaults, see the File Route API reference
* @see https://docs.uploadthing.com/file-routes#route-config
*/
maxFileSize: "32MB",
maxFileCount: 15,
},
video: {
maxFileSize: "32MB",
maxFileCount: 15,
},
"application/zip": {
maxFileSize: "32MB",
maxFileCount: 15,
},
})
// Set permissions and file types for this FileRoute
.middleware(async ({ req }) => {
// This code runs on your server before upload
const user = await auth();

// If you throw, the user will not be able to upload
if (!user) throw new UploadThingError("Unauthorized");

// Whatever is returned here is accessible in onUploadComplete as `metadata`
return { userId: user.userId };
})
.onUploadComplete(async ({ metadata, file }) => {
// This code RUNS ON YOUR SERVER after upload
console.log("Upload complete for userId:", metadata.userId);

console.log("file url", file.ufsUrl);

// !!! Whatever is returned here is sent to the clientside `onClientUploadComplete` callback
return { uploadedBy: metadata.userId };
}),
} satisfies FileRouter;

export type OurFileRouter = typeof ourFileRouter;
import { auth } from "@clerk/nextjs/server";
import { createUploadthing, type FileRouter } from "uploadthing/next";
import { UploadThingError } from "uploadthing/server";

const f = createUploadthing();

// FileRouter for your app, can contain multiple FileRoutes
export const ourFileRouter = {
// Define as many FileRoutes as you like, each with a unique routeSlug

uploader: f({
image: {
/**
* For full list of options and defaults, see the File Route API reference
* @see https://docs.uploadthing.com/file-routes#route-config
*/
maxFileSize: "32MB",
maxFileCount: 15,
},
video: {
maxFileSize: "32MB",
maxFileCount: 15,
},
"application/zip": {
maxFileSize: "32MB",
maxFileCount: 15,
},
})
// Set permissions and file types for this FileRoute
.middleware(async ({ req }) => {
// This code runs on your server before upload
const user = await auth();

// If you throw, the user will not be able to upload
if (!user) throw new UploadThingError("Unauthorized");

// Whatever is returned here is accessible in onUploadComplete as `metadata`
return { userId: user.userId };
})
.onUploadComplete(async ({ metadata, file }) => {
// This code RUNS ON YOUR SERVER after upload
console.log("Upload complete for userId:", metadata.userId);

console.log("file url", file.ufsUrl);

// !!! Whatever is returned here is sent to the clientside `onClientUploadComplete` callback
return { uploadedBy: metadata.userId };
}),
} satisfies FileRouter;

export type OurFileRouter = typeof ourFileRouter;
Here is my api route: 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,
config: {
callbackUrl: `${
process.env.BASE_URL || "http:localhost:3000"
}/api/uploadthing/callback`, // The URL to redirect to after upload
},

// Apply an (optional) custom config:
// config: { ... },
});

export const runtime = "nodejs";
import { createRouteHandler } from "uploadthing/next";

import { ourFileRouter } from "./core";

// Export routes for Next App Router
export const { GET, POST } = createRouteHandler({
router: ourFileRouter,
config: {
callbackUrl: `${
process.env.BASE_URL || "http:localhost:3000"
}/api/uploadthing/callback`, // The URL to redirect to after upload
},

// Apply an (optional) custom config:
// config: { ... },
});

export const runtime = "nodejs";
This is my Callback URL: app/api/uploadthing/callback/route.ts
// This is the UploadThing callback url endopint.
export const POST = async (req: Request) => {
console.log("[UploadThing Callback] POST request received");
const body = await req.json();

console.log("[UploadThing Callback] Request body:");
console.log("\n\n\n --------- \n\n\n");
console.log(body);

console.log("\n\n\n --------- \n\n\n");

if (!body) {
console.error("[UploadThing Callback] No body provided in request");
}

return new Response(
JSON.stringify({
success: true,
message: "Files uploaded successfully",
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
};
// This is the UploadThing callback url endopint.
export const POST = async (req: Request) => {
console.log("[UploadThing Callback] POST request received");
const body = await req.json();

console.log("[UploadThing Callback] Request body:");
console.log("\n\n\n --------- \n\n\n");
console.log(body);

console.log("\n\n\n --------- \n\n\n");

if (!body) {
console.error("[UploadThing Callback] No body provided in request");
}

return new Response(
JSON.stringify({
success: true,
message: "Files uploaded successfully",
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
};
And then last, this is my Client Side Page. app/test/page.tsx
<UploadButton
/**
* @see https://docs.uploadthing.com/api-reference/react#uploadbutton
*/
endpoint="uploader"
onClientUploadComplete={(res) => {
console.log(`onClientUploadComplete`, res);
alert("Upload Completed");
}}
onUploadBegin={() => {
console.log("upload begin");
}}
/>


}
<UploadButton
/**
* @see https://docs.uploadthing.com/api-reference/react#uploadbutton
*/
endpoint="uploader"
onClientUploadComplete={(res) => {
console.log(`onClientUploadComplete`, res);
alert("Upload Completed");
}}
onUploadBegin={() => {
console.log("upload begin");
}}
/>


}
3 Replies
thevictormaina
thevictormaina3mo ago
Disclaimer: I've never used UploadThing before, but I did notice that there seems to be a slight typo in the "app/api/uploadthing/route.ts" file, near "process.env.BASE_URL". There's no double-forward-slashes in the callback url.
𝙈𝙖𝙧𝙫𝙞𝙣𝙆
Thank you for your answer, sadly that was not the problem, tge same problem still persists
godtamara
godtamara3mo ago
I started getting this error too. nothing changed on the server side from my previous working version Figured out the isssue was from my clerk middleware setup. api/uploadthing was not a reachable (public) route

Did you find this page helpful?