Cloudinary showing JSON error in production

285 views Asked by At

I am using this cloudinary function in my nextjs project

import { v2 as cloudinary, UploadApiResponse } from 'cloudinary'
import dotenv from 'dotenv'

 dotenv.config()

const cloudinaryConfig = {
cloud_name: process.env.CloudName as string,
api_key: process.env.CloudapiKey as string,
api_secret: process.env.CloudapiSecret as string,
}

cloudinary.config(cloudinaryConfig)

export default async function uploadPDFtoCloud(
pdfFile: string,
): Promise<string> {
try {
const result: UploadApiResponse = await cloudinary.uploader.upload(
  pdfFile,
  {
    folder: 'file_doc_pdf',
    resource_type: 'raw',
    type: 'authenticated',
  },
)
return result.secure_url as string
} catch (error) {
 console.error('Error Uploading file:', error)
 throw new Error('Failed to upload PDF: ')
}
}

The problem is that this function is working in development normally and returning secure url but while running npm run build to test in production I encountered

Error Uploading file: {
message: `Server return invalid JSON response. Status Code 500. SyntaxError: Unexpected token 
'<', "<!DOCTYPE "... is not valid JSON`,     
name: 'Error',
http_code: 500

While build is still running and each time I test the function when I run the app, I get the same error ,I checked the env variables as all are coming right but after some testing the error is triggering at this code line

const result: UploadApiResponse = await cloudinary.uploader.upload(
  pdfFile,
  {
    folder: 'file_doc_pdf',
    resource_type: 'raw',
    type: 'authenticated',
  },
)

So what might be the problem that causing this error in production and why not in development!?

2

There are 2 answers

0
illia chill On

You should (in your case), upload the file as binary:

//modify code below if needed 
const pdfFile = req.file.buffer.toString('base64');
console.log('pdfFile: ', pdfFile)

You have the error 500 because the server can't handle your pdf. The problem is not cloudinary, the problem is actually how you get pdf file. Other part of your code seems to be ok.

   //mostly probably, you need to indicate base64 type of file 
   cloudinary.uploader.upload(`data:${req.file.mimetype};base64,${pdfFile}`{
            folder: 'file_doc_pdf',
            resource_type: 'raw',
            type: 'authenticated',
   },

P.S. In any case, console.log() you error to see the details P.S 2 : error in production very often relies to .env variables or CORS policy.

0
Alex C. On

Using the cloudinary widget https://next.cloudinary.dev/cldvideoplayer/basic-usage

now I can upload images in production (npm run build) also:

'use client';
import { CldUploadWidget } from 'next-cloudinary';
import { typeSecureUrl } from '../lib/types';
import toast from 'react-hot-toast';

const CloudinaryWidget = ({
  setSecureUrl,
  setPublicid
}: typeSecureUrl) => {
  return (
    <div className='mb-4'>
      {/* // <CldUploadWidget uploadPreset='myuploadpreset'> */}
      <CldUploadWidget
        signatureEndpoint='/pages/api/sign-image'
        options={{
          sources: ['local', 'url', 'unsplash'],
          multiple: false,
          maxFiles: 1,
          tags: ['post'],
          folder: 'posts',
          cropping: true,
          showSkipCropButton: true,
          maxImageFileSize: 100000, // 100K
          maxImageWidth: 800,
          showPoweredBy: false,
          showCompletedButton: true
        }}
        onSuccess={(result: any, { widget }) => {
          if (!result.info) return;

          if (result.event === 'success') {
            // console.log(result.info?.public_id!);
            // console.log(result.info.secure_url!);
            setSecureUrl(result.info.secure_url);
            setPublicid(result.info.public_id);
            toast.success('Immagine scaricata' + result.info?.public_id!);
          } else {
            toast.error('Immagine non scaricata');
          }
          widget.close();
        }}
      >
        {({ open }) => {
          return (
            <>
              <label
                className='mb-2 block text-sm font-medium text-gray-900 dark:text-white'
                htmlFor='file_input'
              >
                Scarica Immagine
              </label>
              <button className='btn btn-primary' onClick={() => open()}>
                Upload
              </button>
            </>
          );
        }}
      </CldUploadWidget>
    </div>
  );
};

export default CloudinaryWidget;