1

I made a transform stream that throws error, error is caught and i need to delete created file, but i get "EPERM: operation not permitted, unlink" when fs.unlink(outPath)

const fs = require('fs');
const http = require('http');
const stream = require('stream');

class myTransform extends stream.Transform {
    constructor(options) {
        super(options);
    }

    _transform(chunk, encoding, callback) {
        const error = new Error();
        error.code = 'LIMIT_EXCEEDED';
        callback(error);
    }
};

const TestStream = () => {
    const stream = fs.createReadStream(__filename, {
        highWaterMark: 40,
        encoding: 'utf-8'
    });

    const outPath = __filename + '.out';

    const writeStream = fs.createWriteStream(outPath)
    const MyTransform = new myTransform()

    stream.pipe(MyTransform).pipe(writeStream);

    MyTransform.on('error', (err) => {
        if (err.code === 'LIMIT_EXCEEDED') {
            fs.unlinkSync(outPath);
            // EPERM: operation not permitted, unlink '.\outPathName.js.out
            return;
        }
    })
}

const server = new http.Server();
server.on('request', (req, res) => {
    res.end('test stream')
    TestStream()
});

server.listen(8000);

can this be fixed and what is the problem

Artem Skibin
  • 111
  • 4

1 Answers1

0

The error is happening because writeStream has not been closed. Try adding writeStream.close().

Before:

MyTransform.on('error', (err) => {
    if (err.code === 'LIMIT_EXCEEDED') {
        fs.unlinkSync(outPath);
        // EPERM: operation not permitted, unlink '.\outPathName.js.out
        return;
    }
})

After:

  MyTransform.on('error', (err) => {
    if (err.code === 'LIMIT_EXCEEDED') {
      writeStream.close();   // Add this
      fs.unlinkSync(outPath);
      // This is error is no longer encountered: EPERM: operation not permitted
      return;
    }
  })

Thank you for sharing reproducible code.

I was sweating over the last 24 hours trying to solve a similar issue on my end. For me, the issue was a little different. I left createReadStream unclosed prior in my code. When doing renameSync, my input_path was still open by createReadStream, so renameSync failed. Doing a close with inputStream.close() fixed the issue for me.

NOT OK

var inputStream = fs.createReadStream(input_path);
// Do stuff
// ...
// A hundred lines later
var outputStream = fs.createWriteStream(output_path, { encoding: 'utf8' });
outputStream.on('close', function () {
    fs.renameSync(output_path, input_path);
    // NOT OK
    // $$ Error: EPERM: operation not permitted, rename 'C:\directoryA\model_dummy_0.txt' -> 'C:\directoryA\model.txt'
    // at Object.renameSync (fs.js:680:3)
    // at WriteStream.<anonymous> (someFile.js:319:14)
    // at WriteStream.emit (events.js:321:20)
    // at internal/fs/streams.js:274:14
    // at C:\someDirectory\node_modules\graceful-fs\graceful-fs.js:61:14
    // at FSReqCallback.oncomplete (fs.js:158:23)
});

OK

var inputStream = fs.createReadStream(input_path);
// Do stuff
inputStream.close();
// ...
// A hundred lines later
var outputStream = fs.createWriteStream(output_path, { encoding: 'utf8' });
outputStream.on('close', function () {
    fs.renameSync(output_path, input_path);
    // OK
});
Chris A.
  • 91
  • 5