Repository navigation
Conversation
validatePath catches ENOENT out of resolveUnicodeEquivalentPath and
reports "Parent directory does not exist". That message never fits the
case it names: when a component is genuinely missing the resolver returns
the joined tail rather than throwing, so create_directory can mkdir -p it.
What does throw ENOENT in there is fs.realpath on an entry that is in the
directory listing but points nowhere. So a dangling symlink reports a
missing parent for a directory that is right there:
Parent directory does not exist: /var/folders/.../mcp-broken-symlink-N9OgbP
Classify it where it happens, at the realpath call, rather than guessing
from an errno two frames up. The existing fallback is left for the other
ENOENT sources in that function, a vanished allowed directory or an
intermediate directory removed mid-walk, where it reads closer to true.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
A symlink pointing at nothing makes the filesystem server report a missing parent directory for a directory that is plainly there.
Server Details
src/filesystem/lib.ts), one new test fileMotivation and Context
validatePathcatches ENOENT out ofresolveUnicodeEquivalentPathand turns it intoThat message never fits the case it names. When a path component is genuinely missing, the resolver does not throw: it returns the joined tail, with a comment saying so, precisely so
create_directorycanmkdir -pit. What does raise ENOENT in there isfs.realpathon an entry that appears in the directory listing but points nowhere.So with an allowed directory
Rholding a danglinglink.txt:Rexists,fs.stat(R)succeeds, and the caller is sent looking at the wrong thing. A stalenode_modules/.binentry gives the same shape.The fix classifies the error where it happens, at the
realpathcall, rather than guessing from an errno two frames up:I left the existing fallback in place. The other ENOENT sources in that function are a vanished allowed directory and an intermediate directory removed mid-walk, where "parent directory does not exist" reads closer to true.
I first tried putting an
fs.stat(parent)check in the catch to tell the two apart. That is worse:__tests__/lib.test.tsauto-mocksfs/promises, sofs.statresolves to undefined and the check passes for both cases. Classifying at the source needs no such guess.How Has This Been Tested?
New
src/filesystem/__tests__/broken-symlink.test.ts, two cases against a real temp directory: a dangling symlink now reportsBroken symlinkwhile its parent still stats fine, and a genuinely missing path still resolves to the joined tail socreate_directorykeeps working. The first fails on current main with the message quoted above.The three failures are in
__tests__/unicode-paths.test.tsand are the same three on unmodifiedmainin this checkout; they look like the composed/decomposed distinction not surviving on APFS. Not touched by this change.Not tested through an LLM client, this is an error-message path.
Breaking Changes
None. No client configuration changes, and the only difference a caller sees is the wording of an error that was already being raised.
Types of changes
Checklist