Repository navigation
Persistent incorrect semantic diagnostic after large rebase or checkout: Module has no exported member #47466
Description
Activity
MartinJohns commented
on Jan 16, 2022 ContributorMore actionsIsn't this fixed by #47274?
MarcCelani-at commented
on Jan 16, 2022 AuthorMore actions#47274 is not fixed. Besides, these may be separate issues, because the way that caches get invalidated for program structure is different than how source file info caches get updated.
This is interesting...
My repro steps:
I have two branches, foo and bar, which include many file changes between them, including a file, "dependenecy.tsx"
- Open VSCode
- Open a file, openfile.tsx, which imports from dependency.tsx
- checkout branch "bar". I see a "FileWatcher:: Triggered" log line for dependency.tsx
- I switch back to "foo". I see "DirectoryWatcher:: Triggered" log lines for dependency.tsx, but I do not see FileWatcher:: Triggered log line should fire for dependency.tsx. With additional logging patched in, I notice that dependency.tsx is never read.
- From henceforth, any branch switches back and forth between foo and bar do not trigger the watch for dependency.tsx
I did not see any FileWatcher:: Closed log lines.
MarcCelani-at commented
on Jan 16, 2022 AuthorMore actionsI have a theory that the issue is this code, which does not properly handle if a file's inode changes:
TypeScript/src/compiler/sys.ts
Lines 1653 to 1659 in 1298f49
return event === "rename" && (!relativeName || relativeName === lastDirectoryPart || (relativeName.lastIndexOf(lastDirectoryPartWithDirectorySeparator!) !== -1 && relativeName.lastIndexOf(lastDirectoryPartWithDirectorySeparator!) === relativeName.length - lastDirectoryPartWithDirectorySeparator!.length)) && !fileSystemEntryExists(fileOrDirectory, entryKind) ? invokeCallbackAndUpdateWatcher(watchMissingFileSystemEntry) : callback(event, relativeName); fs.watch() does not watch a "path", it watches an inode, and the inode for a path can change. The code above does not handle this because if it discovers the file still exists after a rename, it assumes the watch it still good, when there's a very good chance that it's not.
It turns out this is really easy to reproduce with just vim. Repro steps:
- Open a file in VSCode
- tail log and wait for it to calm down
- Open an imported file in vim
- Delete an export that is used in the file opened in VSCode. Issue
:wcommand
When you issue a
:wcommand in vim, it atomically updates the file with an operation that will trigger a rename event.This will trigger the bug and it will manifest one of two ways.
Case 1: FileWatcher will convince itself that it has to close, and you will never see an update for this file again if you do any subsequent writes.Case 2: FileWatcher will trigger but will not close, but after that there will be no more watch events if you do it again.
I suspect git is sometimes (always?) performing some kind of operation like vim is with
:w. Perhaps a large checkout/rebase makes a race condition more likely to occur (race between git updating the file and nodejs processing the watch and checking if the file exists).I confirmed that my git checkout repro is changing the inode with
ls -i. I suspect that the way to fix this is to look at the inode information from statSync.Reacted by Ryan CavanaughMarcCelani-at commented
on Jan 16, 2022 AuthorMore actions(If I am correct, then I am quite certain this issue is different than #47274)
- addedFix AvailableA PR has been opened for this issueA PR has been opened for this issue
on May 6, 2022 OliverJAsh commented
on May 25, 2022 ContributorMore actionsComing here from #44066. If I add these VS Code settings the issue disappears for me, i.e. there are no stale errors when I switch branch (using my test case in #44066):
"typescript.tsserver.watchOptions": { "watchFile": "useFsEvents", "watchDirectory": "useFsEvents" },
Just mentioning it in case it's helpful information for debugging.
MarcCelani-at commented
on May 25, 2022 AuthorMore actionsThis issue is for users of FsEvents, so your suggestion doesn't really apply here. But thanks for commenting!
- locked as resolved and limited conversation to collaborators
on Oct 22, 2025
Bug Report
When using tsserver in VSCode, I sometimes see persistent false error reports from diagnostics after a large rebase or checkout of the form, "Module '{}' has no exported member '{}'." The file mentioned in the error is a file that was updated in the checkout or rebase. Opening the file in question in VSCode loads the file and resolves the incorrect semantic diagnostic. Alternatively, restarting TSServer resolves the incorrect diagnostic
🔎 Search Terms
module has no exported member watch
🕗 Version & Regression Information
This has been happening as long as we can remember
🙁 Actual behavior
persistent incorrect ssemantic diagnostics
🙂 Expected behavior
No errors after a reasonable period of time