ENOENT: no such file or directory, open '/opt/render/project/src/backend/tmp/Test.pdf'

HI I am getting this error constantly - ENOENT: no such file or directory, open ‘/opt/render/project/src/backend/tmp/Test.pdf’. Getting this error only on deploying. The code was running perfectly on my local machine. Please help!

here is my server.js code -

/

/ Import necessary modules
const dotenv = require('dotenv');
dotenv.config()
const express = require("express");
const multer = require("multer");
const fs = require("fs");
const cors = require("cors");
const pdf = require("pdf-parse");
const path = require('path');
const { ChatGoogleGenerativeAI } = require("@langchain/google-genai");
const { HumanMessage } = require("@langchain/core/messages");

// Create an express application
const app = express();
const PORT = process.env.PORT || 3001;
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY;

// Set up CORS middleware
app.use(cors());

app.use(express.json()); // Add this line to parse JSON requests

// Set up storage for uploaded files
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "/opt/render/project/src/backend/tmp/"); // Change the destination path to /tmp/
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  },
});

// Initialize multer upload middleware
const upload = multer({ storage: storage });

// Function to extract text from a PDF file


// Function to ask a question based on the PDF content
async function askQuestion(context, question) {
  const model = new ChatGoogleGenerativeAI({
    modelName: "gemini-pro",
    maxOutputTokens: 2048,
    apiKey: GOOGLE_API_KEY, // Replace "YOUR_API_KEY" with your actual API key
  });

  const response = await model.invoke([
    new HumanMessage(`Context: ${context}\nQuestion: ${question}`),
  ]);
  return response.content;
}

// Route to handle file upload
app.post("/upload", upload.single("pdf"), async (req, res) => {
  try {
    const filePath = "/opt/render/project/src/backend/tmp/";
    console.log(filePath);
    const extractedText = await extractTextFromPDF(filePath);
    res.json({ success: true, text: extractedText });
  } catch (error) {
    console.error("Error reading PDF file:", error);
    res.status(500).json({ success: false, error: "Error reading PDF file" });
  }
});

async function extractTextFromPDF(filePath) {
  try {
    // Ensure filePath is constructed properly and matches where Multer is storing the uploaded file
    const dataBuffer = fs.readFileSync(filePath);
    const data = await pdf(dataBuffer);
    return data.text;
  } catch (error) {
    console.error("Error extracting text from PDF:", error);
    throw error; // Rethrow the error to be caught by the caller
  }
}

// Route to ask a question
app.post("/ask", async (req, res) => {
  const { text, question } = req.body;
  try {
    const answer = await askQuestion(text, question);
    res.json({ success: true, answer: answer });
  } catch (error) {
    console.error("Error answering question:", error);
    res.status(500).json({ success: false, error: "Error answering question" });
  }
});

app.get('/', (req, res) => {
  res.json("heloooouuuuuuu")
})

// Start the server
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

App.jsx code -

import { useState } from 'react';
import axios from 'axios'; // Import Axios for making HTTP requests
function App() {
  const [pdfFile, setPdfFile] = useState(null);
  const [question, setQuestion] = useState("");
  const [answer, setAnswer] = useState("");

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

  const handleQuestionChange = (event) => {
    setQuestion(event.target.value);
  };

  const handleSubmit = async () => {
    if (!pdfFile) {
      alert("Please upload a PDF file.");
      return;
    }

    try {
      const formData = new FormData();
      formData.append("pdf", pdfFile);

      const uploadResponse = await axios.post("https://querydoc-rlsu.onrender.com/upload", formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      });

      console.log("Upload Response:", uploadResponse.data); // Log the response from the upload endpoint

      const extractedText = uploadResponse.data.text;

      const askQuestionResponse = await axios.post("https://querydoc-rlsu.onrender.com/ask", { text: extractedText, question });

      console.log("Ask Question Response:", askQuestionResponse.data); // Log the response from the ask endpoint

      setAnswer(askQuestionResponse.data.answer);
    } catch (error) {
      console.error("Error:", error);
      alert("An error occurred while processing your request.");
    }
  };

  return (
    <div className="App">
      <h1>PDF Question-Answer App</h1>
      <input type="file" onChange={handleFileChange} />
      <br />
      <textarea rows={4} cols={50} placeholder="Enter your question..." value={question} onChange={handleQuestionChange} />
      <br />
      <button onClick={handleSubmit}>Ask Question</button>
      <br />
      {answer && (
        <div>
          <h2>Answer:</h2>
          <p>{answer}</p>
        </div>
      )}
    </div>
  );
}

export default App;

Hi,

There will always be differences between environments: development mode/Local, production mode/Render, etc. These differences need to be considered and configured as required for your own app in each environment.

Render instances have an ephemeral filesystem, meaning any file written to the instance after it has booted (like file uploads) will be lost when it next restarts (e.g. spun down if on free instance type, next deploy, manual restart, etc.).

If you want to use file uploads on your service, you’ll need to have a persistent store, e.g. a Render Disk (which is chargeable and also requires a paid instance type) or an external service like AWS S3.