Skip to content

EBADF thrown by stream if file is explicitly closed in v15 #35862

@alekitto

Description

@alekitto

An unexpected EBADF error is thrown if a stream is open on a file and then the file is explicitly closed.
The explicit close call is required if using fs/promises, otherwise a warning is emitted.

  • Version: v15.0.1
  • Platform: Darwin Kernel Version 19.6.0: Mon Aug 31 22:12:52 PDT 2020; root:xnu-6153.141.2~1/RELEASE_X86_64 x86_64 (macOS Catalina 10.15.7)
  • Subsystem: fs

What steps will reproduce the bug?

I've created a simple case that generates the error.
TESTFILE.txt exists and could be empty.

const fs = require('fs');
const fsPromises = require('fs/promises');

(async () => {
    const handle = await fsPromises.open('TESTFILE.txt', 'r');
    const stream = fs.createReadStream(null, {
        fd: handle.fd,
        autoClose: false,
    });

    await handle.close();
})();

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior?

No error.

What do you see instead?

The following error is thrown:

node:events:304
      throw er; // Unhandled 'error' event
      ^

Error: EBADF: bad file descriptor, read
Emitted 'error' event on ReadStream instance at:
    at emitErrorNT (node:internal/streams/destroy:194:8)
    at errorOrDestroy (node:internal/streams/destroy:257:7)
    at node:internal/fs/streams:193:9
    at FSReqCallback.wrapper [as oncomplete] (node:fs:539:5) {
  errno: -9,
  code: 'EBADF',
  syscall: 'read'
}

If autoClose is omitted or true, the thrown error is:

node:events:304
      throw er; // Unhandled 'error' event
      ^

Error: EBADF: bad file descriptor, close
Emitted 'error' event on ReadStream instance at:
    at emitErrorNT (node:internal/streams/destroy:194:8)
    at emitErrorCloseNT (node:internal/streams/destroy:159:3)
    at processTicksAndRejections (node:internal/process/task_queues:80:21) {
  errno: -9,
  code: 'EBADF',
  syscall: 'close'
}

This last error is thrown also if stream.destroy() is called before handle.close().

The only way to avoid the error is to not call handle.close, but this generates a deprecation warning in a more complex application (Closing a FileHandle object on garbage collection is deprecated.)

Additional information

No error is emitted on previous node versions (10-14).

Metadata

Metadata

Assignees

No one assigned

    Labels

    streamIssues and PRs related to the stream subsystem.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions