Skip to content

fix(runtime): propagate unexpected errno from realpathSync - #1908

Open
wasaybuilds wants to merge 1 commit into
rivet-dev:mainfrom
wasaybuilds:fix/realpath-propagate-unexpected-errors
Open

fix(runtime): propagate unexpected errno from realpathSync#1908
wasaybuilds wants to merge 1 commit into
rivet-dev:mainfrom
wasaybuilds:fix/realpath-propagate-unexpected-errors

Conversation

@wasaybuilds

Copy link
Copy Markdown

Closes #1838.

  • The bridge's realpathSync segment loop special-cased ELOOP/ENOENT/ENOTDIR and break-ed on every other errno, then returned the partially resolved prefix as if it were the resolved path. Callers got a valid-looking wrong path — typically the parent directory — instead of the failure.
  • Unexpected errnos now go through the existing throwNormalizedFsBridgeError, so EACCES and friends reach the guest with the right code, errno, syscall and path.
  • The ENOENT branch now uses createFsError instead of hand-rolling the error, which also gives it the errno field it was missing.

Verified against the real resolution loop with the host lstat stubbed, before and after:

=== BEFORE ===
  realpathSync("/ok/file.txt")                 -> "/ok/file.txt"
  realpathSync("/blocked/secret.txt")          -> "/blocked/secret.txt"
  realpathSync("/blocked/sub/deep/secret.txt") -> "/blocked/sub"
  realpathSync("/missing/x")                   threw ENOENT errno=undefined

=== AFTER ===
  realpathSync("/ok/file.txt")                 -> "/ok/file.txt"
  realpathSync("/blocked/secret.txt")          threw EACCES errno=-13 syscall=realpath
  realpathSync("/blocked/sub/deep/secret.txt") threw EACCES errno=-13 syscall=realpath
  realpathSync("/missing/x")                   threw ENOENT errno=-2

The third line is the reported symptom: a directory path returned where a file was requested, which is what surfaced as EISDIR in the Claude CLI.

I did not add a committed regression test — the only home I found for guest fs semantics is a VM-level suite I can't run locally (no Rust toolchain on this machine). Happy to add one if you point me at the harness you'd want it in.

The segment-resolution loop handled ELOOP, ENOENT and ENOTDIR and broke out
of the loop on every other errno, returning the partially resolved prefix as
if it were the resolved path. A caller hitting EACCES on a path component got
the parent directory back instead of an error.

Unexpected errnos now go through throwNormalizedFsBridgeError so the guest
sees the real failure, and the ENOENT branch uses createFsError so it carries
errno like every other fs error from this bridge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bridge fs: realpathSync silently returns a truncated path when a segment fails with an unexpected error

1 participant