cloudinary_npm
cloudinary_npm copied to clipboard
Unexpected token < in JSON at position 0. Status code 500 in Nextjs 13 production build (App router)
Describe the bug in a sentence or two.
Unexpected token < in JSON at position 0. Status code 500 in Nextjs 13 production build (App router)
Issue Type (Can be multiple)
[ ] Build - Can’t install or import the SDK [ ] Babel - Babel errors or cross browser issues [ ] Performance - Performance issues [X] Behaviour - Functions aren’t working as expected (Such as generate URL) [ ] Documentation - Inconsistency between the docs and behaviour [ ] Incorrect Types - For typescript users who are having problems with our d.ts files [ ] Other (Specify)
Steps to reproduce
Create a route src/app/api/upload/route.ts and use the upload_stream method to upload any image
//src/app/api/upload/route.ts
import { NextRequest, NextResponse } from "next/server";
import { UploadApiResponse, v2 as cloudinary } from "cloudinary";
const cloud_name = process.env.NEXT_CLOUDINARY_CLOUDNAME;
const api_key = process.env.NEXT_CLOUDINARY_API_KEY;
const api_secret = process.env.NEXT_CLOUDINARY_API_SECRET;
cloudinary.config({
cloud_name,
api_key,
api_secret,
});
export async function POST(request: NextRequest) {
const data = await request.formData();
const image = data.get("file") as File;
const bytes = await image.arrayBuffer();
const buffer = Buffer.from(bytes);
const response = await new Promise<UploadApiResponse>((resolve, reject) => {
const stream = cloudinary.uploader.upload_stream({}, (err, res) => {
if (err) reject(err);
resolve(res!);
});
stream.write(buffer);
stream.end();
});
return NextResponse.json({
message: "File successfully uploaded",
url: response.secure_url,
id: response.public_id,
});
}
Run next dev
command and send a request to http://localhost:3000/api/upload
with the image. This works fine
Now, run next build && next start
and send same request to the same url and server will throw an HTTP 500 error:
Error screenshots
Browsers (if issue relates to UI, else ignore)
[ ] Chrome [ ] Firefox [ ] Safari [ ] Other (Specify) [ ] All
Versions and Libraries (fill in the version numbers)
Cloudinary_NPM SDK version 1.41.0 Node - 18.15.0 NPM - 9.6.4
Config Files (Please paste the following files if possible)
// package.json
{
"name": "cloudinary-test",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"cloudinary": "^1.41.0",
"next": "13.5.4",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^5"
}
}
Repository
https://github.com/DongnutLa/cloudinary-next13
Hey @DongnutLa have you tried passing the buffer into the end method? I'm not terribly familiar with the stream API but it's worked for me before. Here's a svelte example https://github.com/cloudinary-community/cloudinary-examples/blob/main/examples/sveltekit-image-upload/src/routes/%2Bpage.server.js#L34
Hey @DongnutLa have you tried passing the buffer into the end method? I'm not terribly familiar with the stream API but it's worked for me before. Here's a svelte example https://github.com/cloudinary-community/cloudinary-examples/blob/main/examples/sveltekit-image-upload/src/routes/%2Bpage.server.js#L34
Yeah, I have already tried that, but I'm getting the same error
Hi @DongnutLa,
Perhaps you can also try something along the lines of:
let cloudinary = require("cloudinary").v2;
let streamifier = require('streamifier');
let uploadFromBuffer = (req) => {
return new Promise((resolve, reject) => {
let cld_upload_stream = cloudinary.v2.uploader.upload_stream(
{
folder: "foo"
},
(error: any, result: any) => {
if (result) {
resolve(result);
} else {
reject(error);
}
}
);
streamifier.createReadStream(req.file.buffer).pipe(cld_upload_stream);
});
};
let result = await uploadFromBuffer(req);
You can find more examples here as well.
Hope you find it useful. Regards, Wissam
@DongnutLa i wasn't quite able to get your repo moving "as is" since there was no UI to work from, however
- I commented out the mimetype and filesize check
- I updated
const buffer ...
toconst buffer = new Uint8Array(arrayBuffer);
- you don't have your
console.error
inside of theif ( err )
check so its going to show up regardless - i removed
stream.write
and instead am usingstream.end(buffer)
and with that i was able to successfully post an image file using formdata from the client
see this PR i set on your reproduction repo: https://github.com/DongnutLa/cloudinary-next13/pull/1/files
oh and important to note, i was never able to reproduce the error you were seeing for some reason...
however i was getting:
[UPLOAD ERROR] TypeError: Cannot read properties of null (reading 'split')
which i think is related to the mimetype code, hence me commenting it out
Hi @DongnutLa,
Perhaps you can also try something along the lines of:
let cloudinary = require("cloudinary").v2; let streamifier = require('streamifier'); let uploadFromBuffer = (req) => { return new Promise((resolve, reject) => { let cld_upload_stream = cloudinary.v2.uploader.upload_stream( { folder: "foo" }, (error: any, result: any) => { if (result) { resolve(result); } else { reject(error); } } ); streamifier.createReadStream(req.file.buffer).pipe(cld_upload_stream); }); }; let result = await uploadFromBuffer(req);
You can find more examples here as well.
Hope you find it useful. Regards, Wissam
It works in development mode, but in a production build fails
@DongnutLa i wasn't quite able to get your repo moving "as is" since there was no UI to work from, however
- I commented out the mimetype and filesize check
- I updated
const buffer ...
toconst buffer = new Uint8Array(arrayBuffer);
- you don't have your
console.error
inside of theif ( err )
check so its going to show up regardless- i removed
stream.write
and instead am usingstream.end(buffer)
and with that i was able to successfully post an image file using formdata from the client
see this PR i set on your reproduction repo: https://github.com/DongnutLa/cloudinary-next13/pull/1/files
I check your changes, but in production build it's still failing
Did you built the app and tried with next start
? Because in development mode it works well, but in production I'm getting the same 500 error.
@DongnutLa if that works in dev mode, try to search for differences between your production and dev environment setups.
hey @DongnutLa i put together this example:
https://github.com/cloudinary-community/cloudinary-examples/tree/main/examples/nextjs-route-handlers-upload
i deployed it on Vercel and it worked as expected
because it didnt include the same options, I also created a separate test just to make sure
https://github.com/colbyfayock/test-nextjs-route-handlers-upload/blob/main/src/app/api/upload/route.ts#L16
i also had no problems with uploading through this mechanism
one thing i did hit was a similar error when trying to upload a file that was too big. this could come from a few different places
though notice the error response
serverless functions have a body size limit: https://vercel.com/guides/how-to-bypass-vercel-body-size-limit-serverless-functions
there are also file size limits depending on your plan from Cloudinary, but higher than that amount: https://support.cloudinary.com/hc/en-us/articles/202520592-Do-you-have-a-file-size-limit-#:~:text=On%20our%20free%20plan%2C%20the,also%20limited%20to%2010%20MB.
where are you deploying your application? the only other consideration is if you're using the vercel Edge runtime but i don't see any configuration in your example using such, as I believe the Node SDK wouldn't be supported there at this time