Amin Baig
Amin Baig

Reputation: 1

Why am I getting this error when trying to upload a file in Nextjs

I have made a small project which takes a csv file and uploads it. it then processes its content to populate mongodb collection

I am getting these two errors:

In VS code console:

API resolved without sending a response for /api/upload, this may result in stalled requests.

and in web app:

Unhandled Runtime Error
Error: Objects are not valid as a React child (found: object with keys {storageErrors}). If you meant to render a collection of children, use an array instead.

Call Stack
throwOnInvalidObjectType
node_modules\react-dom\cjs\react-dom.development.js (14887:0)
createChild
node_modules\react-dom\cjs\react-dom.development.js (15139:0)
reconcileChildrenArray
node_modules\react-dom\cjs\react-dom.development.js (15404:0)
reconcileChildFibers
node_modules\react-dom\cjs\react-dom.development.js (15821:0)
reconcileChildren
node_modules\react-dom\cjs\react-dom.development.js (19167:0)
updateHostComponent
node_modules\react-dom\cjs\react-dom.development.js (19924:0)
beginWork
node_modules\react-dom\cjs\react-dom.development.js (21618:0)
HTMLUnknownElement.callCallback
node_modules\react-dom\cjs\react-dom.development.js (4164:0)
Object.invokeGuardedCallbackDev
node_modules\react-dom\cjs\react-dom.development.js (4213:0)
invokeGuardedCallback
node_modules\react-dom\cjs\react-dom.development.js (4277:0)
beginWork$1
node_modules\react-dom\cjs\react-dom.development.js (27451:0)
performUnitOfWork
node_modules\react-dom\cjs\react-dom.development.js (26557:0)
workLoopSync
node_modules\react-dom\cjs\react-dom.development.js (26466:0)
renderRootSync
node_modules\react-dom\cjs\react-dom.development.js (26434:0)
performConcurrentWorkOnRoot
node_modules\react-dom\cjs\react-dom.development.js (25738:0)
workLoop
node_modules\scheduler\cjs\scheduler.development.js (266:0)
flushWork
node_modules\scheduler\cjs\scheduler.development.js (239:0)
MessagePort.performWorkUntilDeadline
node_modules\scheduler\cjs\scheduler.development.js (533:0)

This is my code for the frontend and API in Nextjs:

Frontend



import { useState } from 'react';

const IndexPage = () => {
  const [selectedFile, setSelectedFile] = useState(null);
  const [uploading, setUploading] = useState(false);
  const [message, setMessage] = useState(null);
  const [error, setError] = useState(null);

  const handleFileChange = (event) => {
    setSelectedFile(event.target.files[0]);
  };

  const handleFileUpload = async () => {
    if (!selectedFile) {
      setError('Please select a file');
      return;
    }

    setError(null);
    setMessage(null);
    setUploading(true);

    const formData = new FormData();
    formData.append('file', selectedFile);

    try {
      const response = await fetch('/api/upload', {
        method: 'POST',
        body: formData,
      });

      const data = await response.json();

      if (response.ok) {
        setMessage(data.message);
      } else {
        setError(data.error);
      }
    } catch (error) {
      setError('Something went wrong');
    } finally {
      setUploading(false);
    }
  };

  return (
    <div>
      <h1>File Upload</h1>

      <input
        name="file"
        type="file"
        accept=".csv"
        onChange={handleFileChange}
      />

      <button
        onClick={handleFileUpload}
        disabled={uploading}
      >
        {uploading ? 'Uploading...' : 'Upload'}
      </button>

      {message && <p>{message}</p>}
      {error && <p>Error: {error}</p>}
    </div>
  );
};

export default IndexPage;

This is the Backend

// pages/api/upload.js

import multer from 'multer';
import csv from 'csv-parser';
import fs from 'fs';
import { MongoClient, ObjectId } from 'mongodb';

const upload = multer({
  dest: 'uploads/', // Directory to store uploaded files
  limits: {
    fileSize: 5 * 1024 * 1024, // Limit file size to 5MB
  },
  fileFilter: (req, file, cb) => {
    if (file.mimetype !== 'text/csv') {
      cb(new Error('Only CSV files are allowed'));
    } else {
      cb(null, true);
    }
  },
});

const saveDistinctValues = async (collectionName, distinctValues) => {
  const client = new MongoClient('mongodb://0.0.0.0:27017/testcsv');
  try {
    await client.connect();
    const db = client.db();
    const collection = db.collection(collectionName);
    await collection.insertMany(distinctValues.map((value) => ({ value })));
  } finally {
    await client.close();
  }
};

const establishRelationships = async () => {
  const client = new MongoClient(process.env.MONGODB_URI);
  try {
    await client.connect();
    const db = client.db();
    const masterCategoryCollection = db.collection('master_category');
    const subCategoryCollection = db.collection('sub_category');
    const productGroupCollection = db.collection('product_group');
    const productCollection = db.collection('product');

    const masterCategories = await masterCategoryCollection.find().toArray();

    for (let i = 0; i < masterCategories.length; i++) {
      const masterCategory = masterCategories[i];
      const subCategory = await subCategoryCollection.findOne({
        value: masterCategory.value,
      });

      const productGroup = await productGroupCollection.findOne({
        value: subCategory.value,
      });

      const products = await productCollection
        .find({
          subCategoryId: { $exists: false },
          masterCategoryId: masterCategory._id,
        })
        .toArray();

      for (let j = 0; j < products.length; j++) {
        const product = products[j];
        await productCollection.updateOne(
          { _id: product._id },
          {
            $set: {
              subCategoryId: subCategory._id,
              productGroupId: productGroup._id,
            },
          }
        );
      }
    }
  } finally {
    await client.close();
  }
};

const handler = async (req, res) => {
  try {
    await upload.single('file')(req, res, async (error) => {
      if (error instanceof multer.MulterError) {
        // Multer error occurred during file upload
        res.status(400).json({ error: error.message });
      } else if (error) {
        // Other errors occurred
        res.status(500).json({ error: 'Something went wrong', error });
      } else if (!req.file) {
        // No file was provided
        res.status(400).json({ error: 'No file uploaded' });
      } else {
        const filePath = req.file.path;
        const masterCategories = [];
        const subCategories = [];
        const productGroups = [];
        const products = [];

        fs.createReadStream(filePath)
          .pipe(csv())
          .on('data', (row) => {
            const masterCategory = row.master_category.trim();
            const subCategory = row.sub_category.trim();
            const productGroup = row.product_group.trim();
            const product = row.product.trim();

            if (masterCategory !== '') {
              masterCategories.push({ value: masterCategory });
            }
            if (subCategory !== '') {
              subCategories.push({ value: subCategory });
            }
            if (productGroup !== '') {
              productGroups.push({ value: productGroup });
            }
            if (product !== '') {
              products.push({ value: product });
            }
          })
          .on('end', async () => {
            // Save distinct values to collections
            await saveDistinctValues('master_category', masterCategories);
            await saveDistinctValues('sub_category', subCategories);
            await saveDistinctValues('product_group', productGroups);
            await saveDistinctValues('product', products);

            // Establish relationships between collections
            await establishRelationships();

            res
              .status(200)
              .json({ message: 'File uploaded and processed successfully' });
          })
          .on('error', (error) => {
            console.error('Error processing CSV:', error.message);
            res.status(500).json({ error: 'Something went wrong' });
          });
      }
    });
  } catch (error) {
    console.error('Error uploading file:', error.message);
    res.status(500).json({ error: 'Something went wrong' });
  }
};

export default handler;

I am unable to understand this error as I am new to Next and React. I have looked around and I believe that the problem is with the way I am using the components!

Upvotes: 0

Views: 225

Answers (2)

yoadev
yoadev

Reputation: 146

You have this error because you are trying to display your error which is an Object.

In this scenario you would either check what error you got from the backend and show a error message related. (Where you have setError(data.error);)

Or

For testing purposes, you can simply display the error as it is, as an object, this way:

{error && <p>Error: {JSON.stringify(error)}</p>}

Upvotes: 0

Samuel Newman
Samuel Newman

Reputation: 184

Your React app is erroring because the error value you're trying to display is an object - you can't put an object directly into the JSX.

error being an object is probably coming from this line, where you've used the key error twice, the second instance overriding the first with the Error object.

 else if (error) {
    // Other errors occurred
    res.status(500).json({ error: 'Something went wrong', error });

Upvotes: -1

Related Questions