Yarn: Garbage characters in Gulp.cmd after first install

Created on 12 Oct 2016  路  13Comments  路  Source: yarnpkg/yarn

Do you want to request a _feature_ or report a _bug_?
Bug

What is the current behavior?
I installed yarn in Windows as per the instructions and then ran yarn in a clean project directory - no existing node_modules. Yarn picked up the package.json file and pulled down all the correct modules.

However, when I attempted to execute gulp using the command .node_modules.bin\gulp it returned the error:
s" was unexpected at this time.

I compared the gulp.cmd file with a version installed using npm3 and there are extra unexpected characters at the end of the file:

@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\..\gulp\bin\gulp.js" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0\..\gulp\bin\gulp.js" %*
)s" %*
)

These characters should not be there: s" %*)

I removed the node_modules and reinstalled and there are no errors now

If the current behavior is a bug, please provide the steps to reproduce.
Steps as per above

What is the expected behavior?
The gulp.cmd should not have any bad characters after install

Please mention your node.js, yarn and operating system version.

  • yarn - 0.15.1
  • node - v4.4.5
  • Windows 7

Additional Info

My package.json file is as follows:

{
  "name": "ci-scripts",
  "version": "1.0.0",
  "description": "CI Support Scripts",
  "main": "gulpfile.js",
  "dependencies": {
    "del": "^2.2.1",
    "gulp": "github:gulpjs/gulp#4.0",
    "gulp-cli": "^1.2.2",
    "jshint": "^2.9.2",
    "lodash": "^4.15.0",
    "node-etcd": "^5.0.3",
    "q": "^1.4.1",
    "request": "^2.74.0",
    "yamljs": "^0.2.8",
    "yargs": "^4.8.1"
  }
}

Most helpful comment

Ok I got this, I couldn't go to sleep with a mistery unanswered 馃槃

The problem is a race condition on cmd-shim, and it only happens with packages that provide the same CLI bin. In this example, both karma-cli and karma provide the bin karma. I'm willing to bet that grunt and gulp have the same situation.

cmd-shim logic:

  • Remove program and program.cmd (if they exist).
  • Write new program and program.cmd.

yarn install logic:

  • Link karma-cli (async)
  • Link karma (async)
  • From cmd-shim('karma-cli'): Remove karma and karma.cmd (if they exist)
  • From cmd-shim('karma'): Remove karma and karma.cmd (if they exist)
  • From cmd-shim('karma-cli'): Write new karma and karma.cmd
  • From cmd-shim('karma'): Write new karma and karma.cmd

So, if the first karma.cmd written is something like this (simplified):
"%~dp0\node.exe" "%~dp0\..\karma-cli\bin.js" %*

Then the final written karma.cmd will be (note the extra 4 chars at the end):
"%~dp0\node.exe" "%~dp0\..\karma\bin.js" %*" %*

Not sure how to solve this though. Without knowing much about how yarn works, it would make sense for yarn to make a "dedupe" of sorts, instead of writing a symlink or exec file that will be overwritten 1ms later. On the other hand, I feel like cmd-shim should be resilient to these kind of things. I'll wait for the opinion of folks more experienced in this codebase than me (i.e. anyone who spent more than 10 minutes reading it).

All 13 comments

For sanity's sake I also just check the bash script after deleting and reinstalling the node_modules and it is also broken

#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")

case `uname` in
    *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac

if [ -x "$basedir/node" ]; then
  "$basedir/node"  "$basedir/../gulp/bin/gulp.js" "$@"
  ret=$?
else 
  node  "$basedir/../gulp/bin/gulp.js" "$@"
  ret=$?
fi
exit $ret
it $ret

That last it $ret should not be there

I'm having a similar issue with grunt. I have this simple install command in package.json scripts:

"install": "grunt build"

yarn executes the command fine (at least it looks that way)

$ grunt build

Bu I get the following error immediately after:

t" build was unexpected at this time.

Feels like certain characters in these commands are problematic, or maybe this is specific to Grunt I'm not sure. I'm running bower, eslint, mocha etc exactly the same way and they work perfectly fine.

My environment details:
Windows 10
Node 6.9.1
npm 3.10.9
yarn 0.16.1
grunt 1.0.1
grunt-cli 1.2.0

Can you reproduce this with yarn@latest? I'm not able to recreate the issue using the latest Yarn v0.17.10. Both gulp and gulp.cmd are correct.

@yerol, I had exactly the same issue and resolved it by deleting node_modules. Something messed up my environment after a series of merges. Can you confirm that fixes it for you too?

@stefda that seems to be the fix. thanks.

I have updated to yarn@latest, bit still the problem happens with Karma :-1:

~An easier fix is to force yarn to regenerate the .bin\* files, for example, running yarn install.~ Doesn't always work.

I'm having the same problem, NodeJS 6.9.1, Yarn 0.18.1 (latest), Windows 10.

By the look of it, it seems like, for some reason, during the initial installation the .bin\* and .bin\*.cmd files are being written twice, first with slightly longer program argument, and then written again with the correct one (without erasing the file first). This is why it only affects short packages (grunt, karma).

Seeing the code of cmd-shim, there's no way the file would be written twice there, so the problem must be in the yarn logic, which is calling cmd-shim twice.

If this rings a bell to any maintainer that would be awesome. If not, I'm willing to help solve this (I'll probably need to read some high-level code structure document, this is a complex codebase).

Ok I got this, I couldn't go to sleep with a mistery unanswered 馃槃

The problem is a race condition on cmd-shim, and it only happens with packages that provide the same CLI bin. In this example, both karma-cli and karma provide the bin karma. I'm willing to bet that grunt and gulp have the same situation.

cmd-shim logic:

  • Remove program and program.cmd (if they exist).
  • Write new program and program.cmd.

yarn install logic:

  • Link karma-cli (async)
  • Link karma (async)
  • From cmd-shim('karma-cli'): Remove karma and karma.cmd (if they exist)
  • From cmd-shim('karma'): Remove karma and karma.cmd (if they exist)
  • From cmd-shim('karma-cli'): Write new karma and karma.cmd
  • From cmd-shim('karma'): Write new karma and karma.cmd

So, if the first karma.cmd written is something like this (simplified):
"%~dp0\node.exe" "%~dp0\..\karma-cli\bin.js" %*

Then the final written karma.cmd will be (note the extra 4 chars at the end):
"%~dp0\node.exe" "%~dp0\..\karma\bin.js" %*" %*

Not sure how to solve this though. Without knowing much about how yarn works, it would make sense for yarn to make a "dedupe" of sorts, instead of writing a symlink or exec file that will be overwritten 1ms later. On the other hand, I feel like cmd-shim should be resilient to these kind of things. I'll wait for the opinion of folks more experienced in this codebase than me (i.e. anyone who spent more than 10 minutes reading it).

We are encountering the same problem as @DanReyLop with karma. Every second/third build on the buildserver fails because the cmd-file is corrupted.
Does someone has a workaround for this problem or is there a bugfix in sight?

@DanReyLop Thanks for sharing!

I just got the same error with npm.

> [email protected] test D:\jenkins\workspace\My Project\frontend
> cross-env NODE_ENV=test jest


s"  was unexpected at this time.
D:\jenkins\workspace\My Project\frontend>)s" 
npm ERR! Test failed.  See above for more details.

This is still happening for me in v0.23.4.
Occurs when doing yarn install for a https://github.com/zurb/foundation-emails-template project.

Platform: Windows 10, i7-45100U, 16GB RAM, slow spinning disk in a laptop.

@farrago please open a new issue with steps to reproduce.

Was this page helpful?
0 / 5 - 0 ratings