nodejs / nodejs/node

fs: fs.link() on exFAT volumes (Windows) fails with misleading EISDIR instead of "not supported"

オープン
#65,817 コメント 6 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

主要言語
JavaScript
スター
122k
フォーク
37.3k
平均マージ
4日 2時間
マージ済み PR(30日)
283

説明

  • Version: v24.19.0
  • Platform: Windows 11 Home (10.0.22631), x64 — NTFS system drive; two USB exFAT volumes (4TB / 2TB)
  • Subsystem: fs
What is wrong?

fs.linkSync(src, dest) targeting a file on an exFAT volume fails with errno EISDIR ("illegal operation on a directory"). The destination path does not exist and is not a directory. The real reason is that exFAT does not support hard links, and the underlying Win32 error is ERROR_INVALID_FUNCTION (WinError 1).

The EISDIR diagnosis actively misleads: it sends developers hunting for a directory that isn't there, instead of pointing at the unsupported filesystem operation.

Reproduction

On an exFAT-formatted volume (e.g. X:\):

$ node -e "require('fs').linkSync('X:\\a.tmp','X:\\b.tmp')"
Error: EISDIR: illegal operation on a directory, link 'X:\a.tmp' -> 'X:\b.tmp'

Python cross-check on the same volume shows the true underlying Win32 error:

$ python -c "import os; os.link(r'X:\a.tmp', r'X:\b.tmp')"
OSError: [WinError 1] 函数不正确。 (ERROR_INVALID_FUNCTION)

Observations from our test matrix (single machine, Windows 11 build 22631, Node v24.19.0):

Target volume Filesystem fs.linkSync result
C:, D:, F: NTFS succeeds
E: (USB), H: (USB) exFAT always fails with EISDIR

The failure splits perfectly along filesystem type, independent of internal/USB. Reads are unaffected; plain file writes work fine on exFAT.

Expected behavior

When CreateHardLinkW fails with ERROR_INVALID_FUNCTION on a filesystem without hard-link support, Node/libuv should surface a meaningful errno — e.g. ENOSYS ("function not implemented"), EPERM, or EOPNOTSUPP — rather than EISDIR.

For reference, on Linux, link(2) on filesystems that do not support hard links reports EPERM/EOPNOTSUPP, and on a system without the syscall at all ENOSYS.

Hypothesis (for upstream to confirm)

Possibly a missing mapping for ERROR_INVALID_FUNCTION in libuv's win32 uv_translate_sys_error, letting the failed uv_fs_link fall through to a misleading errno. We have not traced the exact layer; we only report the observed mapping WinError 1 (ERROR_INVALID_FUNCTION) → EISDIR.

Context / impact

This surfaced while diagnosing a third-party agent tool that publishes files via temp-file + hard-link: on exFAT drives every write failed, and the EISDIR message misattributed the cause. Reported downstream at https://github.com/deepseek-ai/deepseek-harness/discussions/5704 (includes the consumer-side analysis and a fallback-to-rename mitigation).

exFAT is the factory default format for many USB drives and SD cards, so "write to my external drive" is a common end-user scenario that hits this.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

fs.link と uv_fs_link を Windows CreateHardLinkW パスに沿って追跡し、その後、ERROR_INVALID_FUNCTION に対する libuv の uv_translate_sys_error マッピングを調べます。exFAT で再現してマッピングを確認し、結果として得られる errno を対象とするリグレッションテストを追加します。完了条件は、エラーが EISDIR を報告せず、サポートされていない操作を特定することです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
javascript, node.js
領域
operating-systems
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
55/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。