In a production environment, an ENOENT error in Next.js was triggered by fs.readdirSync

Utilizing the Next.js App Router, I attempted to retrieve all my markdown posts stored in files by scanning a directory using fs.readdirSync(). While everything worked flawlessly locally, upon deploying on Vercel, an unexpected issue arose.

The code was encapsulated within a function and invoked twice on different pages. Surprisingly, one of them functioned as intended while the other triggered an error:

Error: ENOENT: no such file or directory, scandir 'data/posts/'
.

Here is the function:

const fs = require('fs');

export async function FetchPosts() {

    // read all markdown files in this dir
    // get an array containing filenames
    let posts = fs.readdirSync('data/posts/');
    
    try {
        let data = [];
        let promises = [];

        posts.forEach((filename) => {
            let promise = new Promise((resolve, reject) => {  
                // use async so i can import module dynamically
                (async () => {
                    // i used a webpack plugin called frontmatter-markdown-loader
                    // this allows me to import markdown files as a module
                    await import(`data/posts/${filename}`)
                        .then((post) => { 
                            // substring is to remove `.md` in the filename
                            const slug = filename.substring(filename.indexOf('.'), 0)
                            resolve({
                                "slug": slug,
                                "attributes": post.attributes,
                                "html": post.html
                            })
                        }
                    )
                })();  
            })
            promises.push(promise);
        })
        data = await Promise.all(promises);

        // sort posts by date
        data.sort((a, b) => {
            let dateA = new Date(a.attributes.date);
            let dateB = new Date(b.attributes.date);
            
            return dateB - dateA;
        })

        return data

    } catch(err) {
        throw err
    }
}

This page functions correctly:

import { FetchPosts } from '@/lib/fetchPosts'

// ...

export default async function Blog() {
    const posts = await FetchPosts();
    
    return (
        <>
            <Header />
            <article>
                <Heading />
                <Padding>
                    <BlogCategories />
                    <BlogList posts={posts} />
                </Padding>
            </article>
        </>
    )
}

However, this triggers

Error: ENOENT: no such file or directory, scandir 'data/posts/'
.

import categories from "@/data/categories.data";
import { FetchPosts } from "@/lib/fetchPosts";

// ...

export default async function Page({ params }) {
    const posts = await FetchPosts();

    let data = [];
    posts?.map((post) => {
        if (post.attributes.category == params.slug)
            data.push(post)
    })

    return (
        <>
            <Header />
            <article>
                <Heading />
                <Padding>
                    <BlogList posts={data} />
                </Padding>
            </article>
        </>
    )
}

Surprisingly, this code builds successfully without any deployment errors. The issue only arises when attempting to access the website.

I'm perplexed and unable to discern the root cause behind this strange behavior.

Answer №1

I managed to resolve this issue by utilizing the path.join() method in my updated code snippet below.

import fs from 'fs/promises';
import path from 'path';

export async function FetchPosts() {
    const postsDirectory = path.join(process.cwd(), 'data/posts/');
    let posts = await fs.readdir(postsDirectory);
    
    try {
        let promises = posts.map(async (filename) => {
            try {
                const post = await import(`data/posts/${filename}`);
                const slug = filename.substring(0, filename.lastIndexOf('.'));
                
                return {
                    "slug": slug,
                    "attributes": post.attributes,
                    "html": post.html
                };
            } catch (error) {
                console.error(`Error importing post ${filename}:`, error);
                throw error;
            }
        });

        let data = await Promise.all(promises);

        data.sort((a, b) => {
            let dateA = new Date(a.attributes.date);
            let dateB = new Date(b.attributes.date);
            
            return dateB - dateA;
        })

        return data

    } catch(err) {
        throw err
    }
}

I also included additional enhancements related to promises. Thank you for taking the time to review this update.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What are some methods for utilizing the data received through this.props.history?

Whenever I need to navigate from one route to another using this.props.history.push("/"), I also want to pass along some extra data. For example: this.props.history.push('/postDetail', {data: item}). However, I am uncertain about where to define ...

Learn how to generate a DataTable in C# by parsing multiple nested JSON Objects efficiently

Whenever I receive dynamic JSON data, it could be a JSON array, a simple JSON object, or nested JSON objects. I am attempting to deserialize and convert the JSON object/array into a DataTable for further processing using Newtonsoft.Json. Here is my curre ...

Vue js throws a maximum call stack error when updating a Chart component

I have successfully created a line chart using the Chart.js 3.5 library. The chart is responsive, all animations are working fine too. I am currently facing an issue where I am attempting to update the data from a parent component and trigger a chart updat ...

Raspberry Pi 4: My LED is only blinking 8 times instead of the expected 16 times

I have encountered an issue with my program run, compilation, and result. In the screenshot below, you can see that my LED is only blinking 8 times instead of the anticipated 16 times. My expectation was for the LED to blink every 0.25 seconds for a total ...

Encountering an undefined error while attempting to retrieve an object from an array by index in Angular

Once the page is loaded, it retrieves data on countries from my rest api. When a user selects a country, it then loads the corresponding cities for that country. Everything is functioning properly up to this point, however, upon opening the page, the city ...

Struggling to integrate Material UI (MUI) into my React application

I have followed all the necessary steps to install materialUI, emotion/react, and emotion/styled in my react app. However, I am encountering an issue where MUI does not seem to work properly. There are no errors displayed on the console or webpage, but not ...

What is the most effective way to access a variable from a service in all HTML files of Angular 2/4 components?

In my angular 4 project, I have an alert service where all components can set alerts, but only specific components display them in unique locations. My question is: how can I access a variable from this service across all HTML files? The structure of my s ...

The Alert dialog in Shadcn will automatically close upon clicking the trigger from the dropdown menu

It seems like other people have encountered this issue, but they all used the alert dialog in the same file. I attempted to open the alert dialog using "" and included a dropdownmenuitem with 'delete' inside it. However, when trying to open the ...

The Stylish Choice: Materialize CSS Dropdown Selector

I am currently integrating Materialize CSS into my application and have used media queries to ensure that the layout is responsive. However, I am facing an issue with a select dropdown element. It works fine on laptops but does not allow for selecting any ...

HTML5 for advanced positioning and layering of multiple canvases

I have 2 canvas layers stacked atop each other, but I need to position them relative to the entire page. The dimensions of both layers are fixed at a width of 800 and a height of 300. My goal is to center the canvas layers regardless of screen size, with ...

creating a new date instance with a specific time zone

Creating a Date object with a dynamically selected timezone is my current goal while I am located in the IST time zone. To avoid the unpredictable behavior of Date.parse(), I am looking for an alternative method. Let's say we set the tzOffset to +05:3 ...

My React component is experiencing issues with the Console.log functionality

Utilizing React for a component, I have incorporated a button that triggers a function 'myFunction' upon clicking, which essentially executes a console.log command. Despite compiling the code without any errors in both Visual Studio and the brow ...

Angular: What is the best way to populate a column in a table with individual dropdown menus in each cell, each containing unique values?

I am completely new to Angular and I am attempting to build a table to display user information. <div ng-controller="ContactController as cc" ng-app="MyApp" id="account-settings-page"> <div class="slds manage-account-table"> <table class="s ...

Error message: "Unable to locate module for split-pane-react in Jest"

Attempting to run Jest tests on my component with [email protected] in a Next.js project using typescript. Encountering the following error: Cannot locate module 'split-pane-react' from 'my component path' when running the test ca ...

I am struggling to set a required input in Angular2

I am new to Angular and currently working on a project that requires input validation to ensure that no field is left blank. The project consists of an HTML file along with a .ts file for functionality. Below is a snippet from the HTML: <div class="f ...

Exploring the world of HighCharts

I am trying to use Highcharts to calculate and visualize the magnitude of a complex number. Currently, my code is displaying the real and imaginary values separately on the graph. However, I seem to be facing issues with the "For loop" that I implemented ...

Facing an issue with the format.js not functioning properly in Rails version 6.1.3

styles.css @import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap"); body { font-family: 'Roboto', sans-serif; color: #333; } .wrapper { max-width: 960px; margin: 0 auto; } button { background ...

Is there a way to trigger a revalidation of a specific page from a client component in NextJS?

The issue Currently, I am in the process of developing a website that utilizes a supabase backend. The main feature of this website is the creation of guides by users. Each guide has a unique dynamic path /guides/[id] as well as an exclusive edit page /gu ...

Using Vue.js to Delete an Element from an Array

I am facing an issue with my form value where the IDs are not getting deleted when I remove data. Each time I save data, a new ID is added to the list in the form value. But when I delete any of those data entries, the corresponding ID is not removed from ...

Enhancing the Performance of jQuery Scripts

My jQuery function called textfill is utilized on numerous div elements. Essentially, it resizes the text inside each div to perfectly fit the container so that longer texts are made smaller than shorter ones while maintaining the maximum font size without ...