bun icon indicating copy to clipboard operation
bun copied to clipboard

Display symlink target path when failing to open one

Open TomasHubelbauer opened this issue 5 months ago • 3 comments
trafficstars

What does this PR do?

Extends the error message when failing to read a symlink with the target path as well as sets the dest field to the target path.

This helps with debugging as it makes it clear to the user the target is ENOENT and not the actual path they are passing to Bun.file. This is borne out of my own confusion at seeing the path exists with ls and seeing the entry in my VS Code Explorer pane, but not realizing the symlink target has been deleted or the path was even a symlink to begin with.

Fixes #17557

  • [x] Code changes

How did you verify your code works?

import { writeFileSync, symlinkSync, unlinkSync } from "fs";
import { join } from "path";

// Create a target file
const targetPath = join(import.meta.dir, "target.txt");
const symlinkPath = join(import.meta.dir, "symlink.txt");

console.log("1. Creating target file:", targetPath);
writeFileSync(targetPath, "Hello from target file");

console.log("2. Creating symlink:", symlinkPath, "->", targetPath);
symlinkSync(targetPath, symlinkPath);

console.log("3. Deleting target file:", targetPath);
unlinkSync(targetPath);

console.log("4. Attempting to open symlink with Bun.file()...");
try {
  const file = Bun.file(symlinkPath);
  console.log("File path:", file.name);
  const content = await file.text();
  console.log("Content:", content);
} catch (error) {
  console.error("Error:", error);
  console.error("Error message:", error.message);
  console.error("Symlink path exists?", await Bun.file(symlinkPath).exists());
}

// Cleanup
try {
  unlinkSync(symlinkPath);
} catch {}

Run using bun bd demo.ts

Before:

1. Creating target file: /Users/tom/Desktop/bun/target.txt
2. Creating symlink: /Users/tom/Desktop/bun/symlink.txt -> /Users/tom/Desktop/bun/target.txt
3. Deleting target file: /Users/tom/Desktop/bun/target.txt
4. Attempting to open symlink with Bun.file()...
File path: /Users/tom/Desktop/bun/symlink.txt
Error: ENOENT: no such file or directory, open '/Users/tom/Desktop/bun/symlink.txt'
    path: "/Users/tom/Desktop/bun/symlink.txt",
 syscall: "open",
   errno: -2,
    code: "ENOENT"

After:

1. Creating target file: /Users/tom/Desktop/bun/target.txt
2. Creating symlink: /Users/tom/Desktop/bun/symlink.txt -> /Users/tom/Desktop/bun/target.txt
3. Deleting target file: /Users/tom/Desktop/bun/target.txt
4. Attempting to open symlink with Bun.file()...
File path: /Users/tom/Desktop/bun/symlink.txt
Error: ENOENT: no such file or directory, open '/Users/tom/Desktop/bun/symlink.txt' -> '/Users/tom/Desktop/bun/target.txt'
    path: "/Users/tom/Desktop/bun/symlink.txt",
    dest: "/Users/tom/Desktop/bun/target.txt",
 syscall: "open",
   errno: -2,
    code: "ENOENT"

I am not skilled in Zig and am a first-time contributor to Bun so I haven't authored the tests yet. I will figure out how to do it but I figured I'd open the pull request first in case there was feedback about a better way to do this or it was immediately clear to the maintainers this is not a fit to go in.

  • [ ] I checked the lifetime of memory allocated to verify it's (1) freed and (2) only freed when it should be

    Not sure how to do that

  • [ ] I included a test for the new code, or an existing test covers it

    Not yet but I will figure out how to do this

  • [ ] JSValue used outside of the stack is either wrapped in a JSC.Strong or is JSValueProtect'ed

    Not dealing with JSValue in this change

TomasHubelbauer avatar Jun 08 '25 21:06 TomasHubelbauer

Nice, can you make a test to verify it works across platforms and not regress in future:)

RiskyMH avatar Jun 09 '25 02:06 RiskyMH

Will do as soon as I'm able to! :)

TomasHubelbauer avatar Jun 09 '25 14:06 TomasHubelbauer

@RiskyMH tests have been added :)

TomasHubelbauer avatar Jun 10 '25 20:06 TomasHubelbauer