reactjsnode.jsnext.jsmerncloudinary

TypeError: Cannot read properties of undefined (reading 'node')


I have a utility function of Cloudinary upload using their SDK. I am working in NEXT JS 14 and server action but encountering an error

TypeError: Cannot read properties of undefined (reading 'node')

When I import my utility function, then I get the error else not. Here are my imports

import uploadToCloudinary from "@/service/uploadToCloudinary"; // works if I comment it out
import { constants } from "@/config";
import { supabase } from "@/lib";
import { isCategoryUnique, isLoggedIn } from "@/middlewares";

uploadToCloudinary.js

const cloudinary = require("cloudinary");

// Configure Cloudinary with your account details
cloudinary.config({
  cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET,
});

// eslint-disable-next-line import/no-anonymous-default-export
export default async (file, folder) => {
  try {
    const { secure_url, public_id } = await cloudinary?.v2?.uploader?.upload(
      file,
      {
        folder,
        upload_preset: process.env.CLOUDINARY_PRESET,
      }
    );

    return {
      success: true,
      data: { secure_url, public_id },
    };
  } catch (error) {
    console.error("Error uploading file to Cloudinary:", error);
    return {
      success: false,
      data: "Internal Server Error",
    };
  }
};


Solution

  • The error is likely occurring because the cloudinary library is trying to access a Node.js environment, but Next.js 14 with Server Actions runs in a different environment called the Edge Runtime.

    The Edge Runtime is a serverless environment provided by Vercel that runs your Server Actions. It's designed to be lightweight and efficient, but it doesn't have access to some Node.js APIs and libraries that rely on them.

    To fix this issue, you'll need to just create an endpoint with the same logic or you use a version of the cloudinary library that is compatible with the Edge Runtime.

    Solution 1 (Endpoint with the same logic):

    import uploadToCloudinary from "@/service/uploadToCloudinary";
    
    export const config = {
      api: {
        bodyParser: {
          sizeLimit: "10mb",
        },
      },
    };
    
    export default async function handler(req, res) {
      if (req.method === "POST") {
        try {
          const file = req.body;
          const folder = "your-folder-name"; // Set the desired folder name for uploaded files
    
          const { success, data } = await uploadToCloudinary(file, folder);
    
          if (success) {
            res.status(200).json(data);
          } else {
            res.status(500).json({ error: data });
          }
        } catch (error) {
          console.error("Error uploading file:", error);
          res.status(500).json({ error: "Internal Server Error" });
        }
      } else {
        res.status(405).json({ error: "Method Not Allowed" });
      }
    }
    

    Solution 2 (Cloudinary library that is compatible with the Edge Runtime) :

    import { Cloudinary } from "@cloudinary/url-gen";
    import { upload } from "@cloudinary/react";
    
    // Configure Cloudinary with your account details
    const cloudinary = new Cloudinary({
      cloud: {
        cloudName: process.env.CLOUDINARY_CLOUD_NAME,
      },
      url: {
        secure: true,
      },
    });
    
    // eslint-disable-next-line import/no-anonymous-default-export
    export default async (file, folder) => {
      try {
        const uploadResult = await upload(file, {
          folder,
          upload_preset: process.env.CLOUDINARY_PRESET,
          cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
        });
    
        return {
          success: true,
          data: {
            secure_url: uploadResult.secure_url,
            public_id: uploadResult.public_id,
          },
        };
      } catch (error) {
        console.error("Error uploading file to Cloudinary:", error);
        return {
          success: false,
          data: "Internal Server Error",
        };
      }
    };
    

    ** This code achieves the desired outcome, but there's likely room for improvement in terms of best practices and code clarity. Since I generated it with AI, I'm still working on optimizing it*