Skip to content

fs.cpSync() aborts the process when the destination is a dangling symlink #67141

Closed

Description

@yohannesjoya

Version

v25.9.0, v26.13.0, main (2500371). Not reproducible on v24.22.2 or v22.20.0.

Platform

Linux x64

Subsystem

fs

What steps will reproduce the bug?

const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');

const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'cp-'));
fs.writeFileSync(path.join(dir, 'src'), 'data');
fs.symlinkSync('missing', path.join(dir, 'dest'));

try {
  fs.cpSync(path.join(dir, 'src'), path.join(dir, 'dest'), { force: true });
  console.log('copied');
} catch (err) {
  console.log('caught', err.code);
}

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

Always.

What is the expected behavior? Why is that the expected behavior?

It prints copied, and dest becomes a regular file, as on v24.22.2 and with fs.promises.cp().

What do you see instead?

The process aborts with exit code 134, and the catch block never runs:

terminate called after throwing an instance of 'std::filesystem::__cxx11::filesystem_error'
  what():  filesystem error: cannot check file equivalence: No such file or directory [<dir>/src] [<dir>/dest]

Additional information

CpSyncCheckPaths in src/node_file.cc calls the throwing overload of std::filesystem::equivalent(src_path, dest_path). The function is the same in v24.22.2 and v25.0.0. The v24 release binary is built with GCC 12 and v25 with GCC 14, so the newer libstdc++ likely reports an error when only one of the two paths exists. I have a fix that uses the std::error_code overload, with a test, and will open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions