protractor: Failed: EPIPE write EPIPE frequently seen when SELENIUM_PROMISE_MANAGER: false

Bug report

  • Node Version: 6.9.1
  • Protractor Version: 5.1.2
  • Angular Version: 4.0.0
  • Browser(s): Chrome Version 57.0.2987.133 (64-bit)
  • Operating System and Version OS X Version 10.10.5 (14F2315)
  • Your protractor configuration file
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/docs/referenceConf.js

/* Third-party */
let HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');
let JUnitXmlReporter = require('jasmine-reporters').JUnitXmlReporter;
let SpecReporter = require('jasmine-spec-reporter').SpecReporter;

/* Custom */
let setup = require('./e2e/setup/setup');

exports.config = {
  allScriptsTimeout: 11000,
  specs: [
    './e2e/**/*.e2e-spec.ts'
  ],
  capabilities: {
    'browserName': 'chrome'
  },
  directConnect: true,
  baseUrl: 'http://localhost:4200/',
  SELENIUM_PROMISE_MANAGER: false,
  framework: 'jasmine',
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000,
    print: function() {}
  },
  useAllAngular2AppRoots: true,
  beforeLaunch: function() {
    require('ts-node').register({
      project: 'e2e'
    });
  },
  onPrepare: function() {
    jasmine.getEnv().addReporter(new SpecReporter());
    jasmine.getEnv().addReporter(new JUnitXmlReporter({
      consolidateAll: true,
      savePath: browser.params.output || 'protractor/log',
      filePrefix: 'protractor_output'
    }));
    jasmine.getEnv().addReporter(new HtmlScreenshotReporter({
      cleanDestination: true,
      dest: 'protractor/log',
      filename: 'index.html'
    }));
    setup();
  }
};
  • A relevant example test
import { browser } from 'protractor';

import { A2Page } from './app.po';
import { NavPartial } from './nav/nav.po';
import { SettingsPage } from './settings/settings.po';
import { Utils } from './utils';

let utils = new Utils();

describe('a2 root', function() {
  let page: A2Page = new A2Page();
  let navPartial: NavPartial = new NavPartial();
  let settingsPage: SettingsPage = new SettingsPage();

  it('should be able to navigate to', () => {
    return page.navigateTo();
  });

  it('should take user to Settings', () => {
    return settingsPage.getTitle().then(title => {
      return expect(title).toEqual('Title');
    }).then(() => {
      return settingsPage.getSubtitle();
    }).then(subtitle => {
      return expect(subtitle).toEqual('Subtitle');
    });
  });

  it('should have a Home menu', () => {
    return page.navigateTo().then(() => {
      return navPartial.isHomePresent();
    }).then(present => {
      return expect(present).toBeTruthy();
    });
  });

  it('should have an Info menu', () => {
    return page.navigateTo().then(() => {
      return navPartial.isInfoPresent();
    }).then(present => {
      return expect(present).toBeTruthy();
    });
  });
});
  • Output from running the test
$ npm run e2e -- --params.baseUrl 'https://myurl'

> a2@0.0.0 pree2e /Users/me/a2
> webdriver-manager update

[13:56:14] I/update - chromedriver: file exists /Users/me/a2/node_modules/protractor/node_modules/webdriver-manager/selenium/chromedriver_2.29.zip
[13:56:14] I/update - chromedriver: unzipping chromedriver_2.29.zip
[13:56:14] I/update - chromedriver: setting permissions to 0755 for /Users/me/a2/node_modules/protractor/node_modules/webdriver-manager/selenium/chromedriver_2.29
[13:56:14] I/update - chromedriver: chromedriver_2.29 up to date
[13:56:14] I/update - selenium standalone: file exists /Users/me/a2/node_modules/protractor/node_modules/webdriver-manager/selenium/selenium-server-standalone-3.4.0.jar
[13:56:14] I/update - selenium standalone: selenium-server-standalone-3.4.0.jar up to date
[13:56:14] I/update - geckodriver: file exists /Users/me/a2/node_modules/protractor/node_modules/webdriver-manager/selenium/geckodriver-v0.16.1.tar.gz
[13:56:14] I/update - geckodriver: unzipping geckodriver-v0.16.1.tar.gz
[13:56:14] I/update - geckodriver: setting permissions to 0755 for /Users/me/a2/node_modules/protractor/node_modules/webdriver-manager/selenium/geckodriver-v0.16.1
[13:56:14] I/update - geckodriver: geckodriver-v0.16.1 up to date

> a2@0.0.0 e2e /Users/me/a2
> $(npm bin)/protractor "--params.baseUrl" "https://myurl"

[13:56:16] I/launcher - Running 1 instances of WebDriver
[13:56:16] I/direct - Using ChromeDriver directly...
Spec started

  a2 root
    ✓ should be able to navigate to
    ✓ should take user to Settings
    ✓ should have a Home menu
    ✗ should have an Info menu
      - Failed: EPIPE write EPIPE

**************************************************
*                    Failures                    *
**************************************************

1) a2 root should have an Info menu
  - Failed: EPIPE write EPIPE

Executed 4 of 4 specs (1 FAILED) in 22 secs.
[13:56:41] I/launcher - 0 instance(s) of WebDriver still running
[13:56:41] I/launcher - chrome #01 failed 1 test(s)
[13:56:41] I/launcher - overall: 1 failed spec(s)
[13:56:41] E/launcher - Process exited with error code 1

npm ERR! Darwin 14.5.0
npm ERR! argv "/Users/me/.nvm/versions/node/v6.9.1/bin/node" "/Users/me/.nvm/versions/node/v6.9.1/bin/npm" "run" "e2e" "--" "--params.baseUrl" "https://myurl"
npm ERR! node v6.9.1
npm ERR! npm  v3.10.8
npm ERR! code ELIFECYCLE
npm ERR! a2@0.0.0 e2e: `$(npm bin)/protractor "--params.baseUrl" "https://myurl"`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the a2@0.0.0 e2e script '$(npm bin)/protractor "--params.baseUrl" "https://myurl"'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the a2 package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     $(npm bin)/protractor "--params.baseUrl" "https://myurl"
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs a2
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls a2
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/me/a2/npm-debug.log

Also excerpt from npm-debug.log:

18 verbose stack Exit status 1
18 verbose stack     at EventEmitter.<anonymous> (/Users/me/.nvm/versions/node/v6.9.1/lib/node_modules/npm/lib/utils/lifecycle.js:255:16)
18 verbose stack     at emitTwo (events.js:106:13)
18 verbose stack     at EventEmitter.emit (events.js:191:7)
18 verbose stack     at ChildProcess.<anonymous> (/Users/me/.nvm/versions/node/v6.9.1/lib/node_modules/npm/lib/utils/spawn.js:40:14)
18 verbose stack     at emitTwo (events.js:106:13)
18 verbose stack     at ChildProcess.emit (events.js:191:7)
18 verbose stack     at maybeClose (internal/child_process.js:877:16)
18 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:226:5)
  • Steps to reproduce the bug
  1. Use approximately the Node and Angular versions mentioned, Chrome browser, possibly Mac OS X. (Not yet certain how specific issue is to that combination.)
  2. Set SELENIUM_PROMISE_MANAGER: false in config (disable control flow).
  3. Due to (2) above, use promises everywhere in your test suite.
  4. Have a suite that for each of several tests, gets a URL and clicks or checks element presence.
  5. Very quickly you will start hitting Failed: EPIPE write EPIPE errors unpredictably.

I’m not using await. I cannot identify any unhandled promises in the test code either (and I’m experienced with promises), although that has been suggested in some of the comments, so I have to allow for that possibility. Still, it’s surprising that node would crash on an unhandled promise, if that’s the case. So it seems there’s a node bug in here somewhere, in addition to whatever problem there may be in my test or protractor or webdriver, etc.

  • The URL you are running your tests against (if relevant)

Sorry, it’s not public.

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 13
  • Comments: 47 (7 by maintainers)

Most upvoted comments

In our project EPIPE errors were appearing, because tests (in TypeScript) were incorrectly using awaits. And therefore unhandled Promise rejections were happening randomly and leading to these errors. Once I’ve fixed incorrect usages we don’t have these errors anymore on Node 8.

Try to check your tests carefully for incorrect usages of await (either missing or redundant) or just incorrect Promise chaining (for example when you forgot to return Promise from helper methods). In our case typical error was using:

browser.wait(await EC.invisibilityOf(fade)); // incorrect

instead of:

await browser.wait(EC.invisibilityOf(fade)); // correct

Maybe it will help somebody, who also has this issue.

@renehamburger thank you. After add this one to onPrepare section of my protractor.conf.js:

let currentCommand = Promise.resolve();
// Serialise all webdriver commands to prevent EPIPE errors
const webdriverSchedule = browser.driver.schedule;
browser.driver.schedule = (command, description) => {
   currentCommand = currentCommand.then(() =>
      webdriverSchedule.call(browser.driver, command, description)
    );
    return currentCommand;
};

Error ‘Failed: EPIPE write EPIPE’ is gone.

I am seeing the error in node v8.0.0

Using Async/await seems to be a bigger mess than the controlFlow.

The error is still observed on Mac OS Sierra even after trying the above solution.

Is there any other solution that can try.

Thanks

I think this might be triggered by the same situation as some other similar errors, the fix for which is to use HTTP keep-alive in the communication between the Selenium Node code and the browser. There is a fix for this in the Selenium mainline, last year - but it is not published in any version of that code.

Here is the workaround we use here, borrowed and edited from something another commenter wrote in another issue. Set up a NPM package.script to run it:

"scripts": {
    "install": "webdriver-manager update && node keep-alive-patch.js",

The patcher code is:

const fs = require('fs');
const chromeFile = 'node_modules/selenium-webdriver/chrome.js';
fs.readFile(chromeFile, 'utf8', function (err, data) {
  if (err)
    throw err;

  const result = data.replace(/new http.HttpClient\(url\)/g,
    "new http.HttpClient(url, new (require('http').Agent)({ keepAlive: true }))");
  console.log(`Patching ${chromeFile}`);
  fs.writeFileSync(chromeFile, result, 'utf8');
});

With this patch, Protractor is 99%+ robust for us on both Windows and OSX, using SELENIUM_PROMISE_MANAGER: false. Your mileage may vary, depending on whether your EPIPE error is caused by the same underlying situation as ours way.

The issue here and in #4507 seems to be concurrent webdriver commands. @wvanderdeijl suggested a solution for the particular case of ElementArrayFinder::map() in #4508. Until this is resolved properly, the following wrapper for browser.driver.schedule(), which creates a queue to prevent any concurrent webdriver commands being executed, might be a workaround.

Can someone who’s experiencing EPIPE-errors regularly test this? It may slow down the test execution to some degree.

The following code can be called in Protractor’s onPrepare() hook, for example.


let currentCommand = Promise.resolve();
// Serialise all webdriver commands to prevent EPIPE errors
const webdriverSchedule = browser.driver.schedule;
browser.driver.schedule = (command: Command, description: string) => {
  currentCommand = currentCommand.then(() =>
    webdriverSchedule.call(browser.driver, command, description)
  );
  return currentCommand as any;
}

or with some additional logging:

let currentCommand = Promise.resolve();
let concurrencyCounter = 0;
// Serialise all webdriver commands to prevent EPIPE errors
const webdriverSchedule = browser.driver.schedule;
browser.driver.schedule = (command: Command, description: string) => {
  console.log(`${++concurrencyCounter} concurrent webdriver command(s). Latest command: ${description}`);
  currentCommand = currentCommand.then(() =>
    webdriverSchedule.call(browser.driver, command, description)
      .then(result => {
        concurrencyCounter--;
        return result;
      })
      .catch(error => {
        concurrencyCounter--;
        //console.lgErrLabel('Webdriver error')(command, description, error);
        console.error('Webdriver error:', command, description, error);
        throw error;
      })
  );
  return currentCommand as any;
}

@yyankowski Yes, it was my experience as well. I saw this error happening with $$ more than anything else. Especially, when trying to call a method on the ElementArrayFinder returned by $$.

@CrispusDH - I used to think the same thing until I kept getting issues around tests failing for reasons I couldn’t understand. I went back and added await inside my except() statements and that cleared them up.

Do we have some link to Protractor roadmap? Or it doesn’t exist at all

@Xaz16: Worked for us as workaround, thanks!

But the “EPIPE write EPIPE” erroms seems to be a bug in Selenium: https://github.com/SeleniumHQ/selenium/issues/5345 which will be solved in 4.0.0.

So we have to wait until Protractor uses 4.0.0 version and the we can remove this workaround.

Got these error very often lately with SELENIUM_PROMISE_MANAGER:false When running multiple tests

@demisx no you are wrong , maybe thats why you get still EPIPE errors 💃 Yes - it returns ElementArrayFinder w/o await but you wont be able to iterate over it and this part would not work

for (let element of l){
            text = await element.getText();
            labels.push(text)
        }

if i do await, I get a list of elements 😉 that I can go through

@demisx this is mainly happening for me for each , filter and other functions that are used iwth arrays

how I reworked it

        // EPIPE write EPIPE
        // await $$("short-list-component.ng-valid mat-label").each(async function (element) {
        //     labels.push(await element.getText())
        // });
        // this.logInfo("getMatLabels: " + labels);
        // return labels

        let l = await $$("q-short-list-component.ng-valid mat-label");
        for (let element of l){
            text = await element.getText();
            labels.push(text)
        }

any ETA for 4.0.0-alpha.1 included in protractor?

@kahan002

We finally solved it using this code

function patchSchedule() {
  if (os.platform() === 'darwin') {
    let currentCommand = Promise.resolve();
    let concurrencyCounter = 0;
    // Serialise all webdriver commands to prevent EPIPE errors
    const webdriverSchedule = browser.driver.schedule;
    browser.driver.schedule = (command: Command, description: string) => {
      currentCommand = currentCommand.then(() =>
        webdriverSchedule
          .call(browser.driver, command, description)
          .then(result => {
            concurrencyCounter--;
            return result;
          })
          .catch(error => {
            concurrencyCounter--;
            // tslint:disable-next-line:no-console
            console.error('Webdriver error:', command, description, error);
            throw error;
          })
      );
      return currentCommand as any;
    };
  }
}

which is called in protractor.conf.ts

onPrepare: () => { patchSchedule(); },

#4792 did not fix the problem for me. Still getting Failed: EPIPE write EPIPE error 1 out of 5 doing filtering on ElementArrayFinder:

$$('classified-section').filter((section) => section.isDisplayed())

Please upgrade to selenium-webdriver@4.0.0-alpha.1. It seems to be resolved there.

Thanks @Mokkapps for sharing that. A couple of notes in case someone wants to adapt it for typeScript and an environment like mine. os.platform() was not known, so I used process.platform. I had to import { Command } from "selenium-webdriver"; I had to comment out the concurrencyCounter since it was never read. And since I have typeScript warning on implicit any, I needed to make them explicit in .then((result : any) => { and .catch((error: any) => {. I am not complaining about the code, and I am happy you shared it (it seems to fix the issue, though it’s a bit hard to tell since it was intermittent). I hope that this comment is helpful to someone. Thanks so much for getting back to me and others. But perhaps my changes broke your fix, because I just got UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): Error: EPIPE write EPIPE (node:8514) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. after all. I’ll go back and see where I must be misusing await.

@Mokkapps At least in TypeScript your code gives the error: Type ‘<T>(command: Command, description: string) => Promise void’ is not assignable to type ’ T (command: Command, description: string) => Promise T’. Type ‘Promise void’ is not assignable to type ‘Promise T’. Property ‘cancel’ is missing in type ‘Promise void’.

@CrispusDH I had to change the code snippet to

let currentCommand = Promise.resolve(); // Serialise all webdriver commands to prevent EPIPE errors const webdriverSchedule = browser.schedule; browser.schedule = (command, description) => { currentCommand = currentCommand.then(() => webdriverSchedule.call(browser, command, description) ); return currentCommand; };

So basically remove the .driver

@renehamburger I think you are spot on there. I narrowed down most of my errors were coming from functions which returns a Promise.all call so i’m quite sure it must have something to do with concurrency