Since you've tried with Promises, I'll show you how to do it with Promises
Using async/await especially makes this really easy
Note: since I don't know how you are using fs the import/require only gets the promise versions of readdir and readFile, and uses it like readdir rather than fs.readdir - so other existing code won't break
const {readFile, readdir} = require('fs/promises');
// if you use import (modules) instead of require (commonjs)
// import { readFile, readdir } from 'fs/promises';
app.get('/students/:record_id', async function (req, res) {
    var record_id = req.params.record_id;
    var dirname = "students/";
    try {
        const filenames = await readdir(dirname);
        for (let filename of filenames) {
            const data = await readFile(dirname + filename, "utf-8");
            if (data.includes(record_id)) {
                return res.status(200).send(data);
            }
        }
        res.status(404).send({"message": "error - student not found"});
    } catch (err) {
        onError(err);
        res.status(500).send({"message": "internal server error"});
    }
});
Note: I wouldn't send a 500 (Internal Server Error) if a student is not found - I changed the logic to send 404 (not Found) instead - which is more appropriate
If you want pure promise (no async/await) - I believe the following is one way to do it, probably not the nicest code, but it should work (haven't tested though)
const {readFile, readdir} = require('fs/promises');
// if you use import (modules) instead of require (commonjs)
// import { readFile, readdir } from 'fs/promises';
app.get('/students/:record_id', function (req, res) {
    var record_id = req.params.record_id;
    var dirname = "students/";
    
    let p = Promise.resolve(false);
    for (let filename of filenames) {
        p = p
        .then(found => 
            found ? found : readFile(dirname + filename, "utf-8")
            .then(
                data => 
                    data.includes(record_id) ? data : false
            )
        );
    }
    .then(data => data ? res.status(200).send(data) : res.status(404).send({"message": "error - student not found"}))
    .catch(err => {
        onError(err);
        res.status(500).send({"message": "internal server error"});
    })
});
And, finally - without using Promises at all
app.get('/students/:record_id', function (req, res) {
    let found = false;
    const record_id = req.params.record_id;
    const dirname = "students/";
    const filenames = fs.readdirSync(dirname);
    const count = filenames.length;
    const checkFile = index => {
        if (index < count) {
            const filename = filenames[index];
            fs.readFile(dirname + filename, "utf-8", function (err, data) {
                if (err) {
                    onError(err);
                    res.status(500).send({"message": "internal server error"});
                } else if (data.includes(record_id)) {
                    res.status(200).send(data);
                } else {
                    checkFile(index + 1)
                }
            });
        } else {
            res.status(404).send({"message": "error - student not found"});
        }
    }
    checkFile(0);
});