I can’t believe the number of hours I’ve burned trying to figure this out. The gist of this story is that npm install in a vagrant virtual environment sometimes makes some REALLY long paths and it makes Windows freak out with EPERM, EACCESS, and UNKNOWN symlink errors. The solution is to edit a Vagrant file and wait until a proper fix is committed into the official Vagrant repo.

Let me back up for a minute for a little background…

I’ve been using Laravel Homestead (an official Vagrant box) since last summer when I dumped WAMP because of one too many weird quirks. Homestead is made primarily for Laravel development, but I also successfully used it for WordPress development since it’s a nice, well-built, all around LEMP stack.

I’m not exactly sure when it all started, but I began having trouble running the npm install command. Sometimes running npm cache clean would fix it, maybe run as sudo, and sometimes running it from within the windows environment instead of the vagrant environment (or vice versa) would allow it to run. Running it from windows was probably the dumbest workaround because I specifically didn’t want all that stuff (*EMP, Node, etc) in my windows environment to begin with! But eventually it just refused to work on multiple vagrant dev sites no matter what I did so I gave up and decided to destroy the vagrant box and start all over.

Well, that didn’t fix it either and probably made it even worse. Since it was a new VM I decided to fiddle with several npm versions and several node versions. I updated vagrant, virtualbox, the Homestead box configuration, and anything else I could think of. I even decided to try a different Vagrant box configuration and tried VVV (which is really nice, btw). Turning off backups and anti-virus had no effect either. Nothing worked.

Screenshot npm install errors
Screenshot npm install errors

The error…

Here is a sample of one of the many (MANY) error messages that came up.

Error: EPERM, open '/srv/www/harvsworld/htdocs/wp-content/themes/harvsworld/node_modules/gulp-imagemin/node_modules/imagemin/node_modules/imagemin-optipng/node_modules/optipng-bin/node_modules/bin-wrapper/node_modules/download-status/node_modules/lpad-align/package.json'

The EPERM error implies a permission issue and npm suggests you run as sudo. Here’s a hint… It doesn’t work.

Off to google I go…

The trip down the rabbit hole that eventually led to my solution started by finding this link to a forum post titled Cannot install Elixir on Homestead on the excellent laracasts.com video learning site (focused on Laravel). This is where I figured out the error is probably due to the length of paths being too long for windows (see the length of that path in the error above). At the bottom of the forum thread is a link to the real issue on the Vagrant github: support long paths on windows hosts, by rebinding the share to a UNC path.

The fix…

Scroll down through the thread until you get to the fix by chernetsov0 and celtric. Your installation may vary, but this worked for me. In the file: C:\HashiCorp\Vagrant\embedded\gems\gems\vagrant-1.7.2\plugins\providers\virtualbox\driver\version_4_3.rb between lines 495-510. Replace the line folder[:hostpath] with '\\\\?\\' + folder[:hostpath].gsub(/[\/\\]/,'\\')]. The explanation of what it’s doing is in the github link. MAKE A BACKUP FIRST :)

UPDATE: Looks like this was changed in 1.7.3+.

Here is the filepath for me:

C:\HashiCorp\Vagrant\embedded\gems\gems\vagrant-1.7.4\plugins\providers\virtualbox\driver

And the new code looks like this:

def share_folders(folders)
  folders.each do |folder|
	hostpath = folder[:hostpath]
	args = ["--name",
	  folder[:name],
	  "--hostpath",
	  hostpath]
	args << "--transient" if folder.key?(:transient) && folder[:transient]

	# Enable symlinks on the shared folder
	execute("setextradata", @uuid, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/#{folder[:name]}", "1")

	# Add the shared folder
	execute("sharedfolder", "add", @uuid, *args)
  end
end

Which I replace with:

def share_folders(folders)
  folders.each do |folder|
	hostpath = '\\\\?\\' + folder[:hostpath].gsub(/[\/\\]/,'\\')
	args = ["--name",
	  folder[:name],
	  "--hostpath",
	  hostpath]
	args << "--transient" if folder.key?(:transient) && folder[:transient]

	# Enable symlinks on the shared folder
	execute("setextradata", @uuid, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/#{folder[:name]}", "1")

	# Add the shared folder
	execute("sharedfolder", "add", @uuid, *args)
  end
end

This fix has been removed though in 1.7.4 going forward for both 4.3.x and 5.x until further testing. Digging through Github issue #5933 it appears that VirtualBox 5 doesn’t like the UNC file paths as it was implemented here and this was removed until something else can be figured out.

As I write this update on August 29th, only VirtualBox 5 works with Windows 10 (which I just upgraded to) and that means I cannot use my Vagrant boxes. And from the comments it appears I’m not alone…

Well almost…

That fix got me pretty far, but then just when I thought I was in the clear I ran into *this* error:

npm ERR! UNKNOWN, symlink '../strip-ansi/cli.js'

The way I got around that was with npm install --no-bin-links, a command I got from the first link at laracasts and this link at askubuntu.com which tells npm to not create any symlinks during installation.

And voilà! All fixed up.

Parting thoughts… the lengths of some of these paths that npm (and the various dependencies) creates borders on the ridiculous. More importantly, the paths it makes shouldn’t have any influence on the host system since that’s the reason we use these virtual environments in the first place.