Local plugin directory resolver treats .DS_Store as a plugin, logging 'Failed to load plugin dependencies ... ENOTDIR' on every start
Bug Description
LocalDirectoryPluginDeployerResolver.resolveFromLocalPath treats every entry in
the directory as a plugin, including dotfiles. On macOS the Finder drops a
.DS_Store into any folder a user has ever looked at, so a local-dir: plugin
directory the user has opened produces this on every application start:
root ERROR Failed to load plugin dependencies from '/Users/…/plugins/.DS_Store': Error: ENOTDIR: not a directory, open '/Users/…/plugins/.DS_Store/package.json'The error is harmless — the real plugins still deploy — but it is alarming, permanent, and sends people looking for a broken plugin that does not exist.
Steps to Reproduce
- Point the app at a local plugin directory, e.g.
THEIA_PLUGINS=local-dir:/path/to/plugins. - Open that directory in Finder once (or
touch /path/to/plugins/.DS_Store). - Start the app and read the backend log.
Expected
No error. Dot-prefixed entries are not plugins and should be ignored.
Actual
Failed to load plugin dependencies … ENOTDIR on every start, once per dotfile.
Cause
packages/plugin-ext/src/main/node/resolvers/local-directory-plugin-deployer-resolver.ts:
protected async resolveFromLocalPath(pluginResolverContext: PluginDeployerResolverContext, localPath: string): Promise<void> {
const files = await fs.readdir(localPath);
files.forEach(file =>
pluginResolverContext.addPlugin(file, path.resolve(localPath, file))
);
}Every name is added unconditionally, so .DS_Store becomes a plugin id and the
deployer later tries to read .DS_Store/package.json.
Suggested Fix
Skip dot-prefixed entries. A plugin directory never begins with a dot, so nothing is lost:
protected async resolveFromLocalPath(pluginResolverContext: PluginDeployerResolverContext, localPath: string): Promise<void> {
const files = await fs.readdir(localPath);
- files.forEach(file =>
- pluginResolverContext.addPlugin(file, path.resolve(localPath, file))
- );
+ files.forEach(file => {
+ if (file.startsWith('.')) {
+ // e.g. the .DS_Store the macOS Finder drops into any folder it displays
+ return;
+ }
+ pluginResolverContext.addPlugin(file, path.resolve(localPath, file));
+ });
}This is what we ended up shipping downstream as a subclass override, and it removes the error without affecting plugin discovery.
Same shape of noise appears for any other stray dotfile in the directory
(._* AppleDouble files from a copy off a non-HFS volume, for instance).
Versions
- Reproduced on
@theia/plugin-ext1.57.0, macOS (Electron). resolveFromLocalPathis unchanged onmasteras of today, somasteris affected: https://github.com/eclipse-theia/theia/blob/master/packages/plugin-ext/src/main/node/resolvers/local-directory-plugin-deployer-resolver.ts
Happy to open a PR if useful — I have not signed the ECA yet, so I have filed this as an issue rather than let a PR sit blocked on validation.
Source: eclipse-theia/theia