got icon indicating copy to clipboard operation
got copied to clipboard

Cannot read property 'includes' of undefined

Open zckrs opened this issue 3 years ago • 16 comments

Describe the bug

Hi, we use got in many microservice and yesterday we upgrade v11.5.2 to v11.7.0.

Since this upgrade we have some error

RequestError: Cannot read property 'includes' of undefined
    at /src/node_modules/got/dist/source/core/index.js:1246:38
    at Request._beforeError (/src/node_modules/got/dist/source/core/index.js:1273:11)
    at ClientRequest.<anonymous> (/src/node_modules/got/dist/source/core/index.js:959:18)
    at Object.onceWrapper (events.js:422:26)
    at ClientRequest.emit (events.js:327:22)
    at ClientRequest.origin.emit (/src/node_modules/@szmarczak/http-timer/dist/source/index.js:39:20)
    at Socket.socketErrorListener (_http_client.js:426:9)
    at Socket.emit (events.js:315:20)
    at emitErrorNT (internal/streams/destroy.js:92:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
    at Object.calculateRetryDelay [as default] (/src/node_modules/got/dist/source/core/calculate-retry-delay.js:9:44)
    at /src/node_modules/got/dist/source/core/index.js:1236:71
    at Request._beforeError (/src/node_modules/got/dist/source/core/index.js:1273:11)
    at ClientRequest.<anonymous> (/src/node_modules/got/dist/source/core/index.js:959:18)
    at Object.onceWrapper (events.js:422:26)
    at ClientRequest.emit (events.js:327:22)
    at ClientRequest.origin.emit (/src/node_modules/@szmarczak/http-timer/dist/source/index.js:39:20)
    at Socket.socketErrorListener (_http_client.js:426:9)
    at Socket.emit (events.js:315:20)
    at emitErrorNT (internal/streams/destroy.js:92:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3

Do you have any ideas why ? This related to a breaking change ?

  • Node.js version: 12
  • OS & version: Linux

Actual behavior

Throw a strange error independant of our code.

Expected behavior

Should work like v11.5.2

Checklist

  • [X] I have read the documentation.
  • [X] I have tried my code with the latest version of Node.js and Got.

zckrs avatar Sep 22 '20 10:09 zckrs

Can you provide some code to reproduce the issue, thanks.

Giotino avatar Sep 22 '20 12:09 Giotino

The bug not occurs each time. A reproduce code is complicated to provide but something similar is:

got(`http://${ip}/${uri}`, {
    method: 'PURGE',
    port: 8080,
    responseType: 'text',
    headers: {
      'X-Forwarded-Proto': 'https',
      Host: domain
    }
  });

Used in kubernetes pod to purge cache on varnish.

I suspect usage of method purge with the recent change on retry feature provided by got.

zckrs avatar Sep 22 '20 12:09 zckrs

Are you using options.retry? Your error seems to be due to an undefined options.retry.methods.

It could be Got that fails to merge the defaults of options.retry with your custom ones.

Giotino avatar Sep 22 '20 13:09 Giotino

No, we use got.extend to add some default option but not on retry.

const rfGot = got.extend({
  dnsCache: true,
  headers: {
    'user-agent': `rf-got (${podNamespace} ${hostname})`
  },
  timeout: 10000,
  responseType: 'json',
  handlers: [
    (options, next) => {
      const {context, url}: {context: RfGotContext; url: URL} = options;

      if (!context.token) {
        const xQueryToken = uuidV4();
        options.headers['x-query-token'] = xQueryToken;
        logger.warn(null, xQueryToken, `rf-got generate new X-Query-Token for url ${url.toString()}`);
        return next(options);
      }

      options.headers['x-query-token'] = context.token;

      return next(options);
    }
  ],
  hooks: {
    beforeError: [
      error => {
        const {request} = error;
        if (request) {
          error.message += ` (requestUrl: ${request.requestUrl})`;
        }

        return error;
      }
    ]
  }

});

zckrs avatar Sep 22 '20 13:09 zckrs

Hi @zckrs, I can see that got restricts the method. How is it that you are calling with PURGE? Forgive me if this query is out of context of the issue.

prithvijit-dasgupta avatar Sep 22 '20 17:09 prithvijit-dasgupta

@prithvijit-dasgupta we just used method option.

@Giotino I can confirm the bug occur at 11.6.0. diff 11.5.2...11.6.0

zckrs avatar Sep 23 '20 08:09 zckrs

@prithvijit-dasgupta It's just a TypeScript type. You can still force it to accept non standardized methods.

szmarczak avatar Sep 23 '20 10:09 szmarczak

@zckrs Are you able to reproduce the bug?

szmarczak avatar Oct 01 '20 20:10 szmarczak

I can reproduce when I upgrade got > v11.6.0

zckrs avatar Oct 01 '20 21:10 zckrs

But are you able to reproduce the bug consistently? Every time? Could you please scratch an example on RunKit or a repo?

szmarczak avatar Oct 01 '20 21:10 szmarczak

Here's a public RunKit: https://runkit.com/marianvasile/got-retry-issue

MarkVasile avatar Oct 04 '20 03:10 MarkVasile

nvm, in my case it was (line 12) the options.retry that was causing the error.

MarkVasile avatar Oct 04 '20 05:10 MarkVasile

@MarianVasile the options aren't renormalized. We should add this to the docs.

szmarczak avatar Oct 04 '20 09:10 szmarczak

My problem seems to fix with v11.8.0.

Maybe a bug inside one dependence.

zckrs avatar Dec 11 '20 11:12 zckrs

Hi,

In fact this issue already exists.

The bug occur only for custom method. Our case is to invalidate a entry in Varnish cache by a PURGE http method.

return pMap(ipCacheLPods, ip => rfGot(`http://${ip}/${uri}`, {
            method: 'PURGE',
            port: varnishPort,
            responseType: 'text',
            headers: {
              'X-Forwarded-Proto': 'https',
              Host: domain,
            },
          }, {concurrency: 2}));
        });

With this code we get a error Cannot read property 'includes' of undefined from the line const hasMethod = retryOptions.methods.includes(error.options.method);

If we add a retry option with method PURGE

return pMap(ipCacheLPods, ip => got(`http://${ip}/${uri}`, {
            retry: {
              methods: ['PURGE'],     <==================
            },
            method: 'PURGE',
            port: varnishPort,
            responseType: 'text',
            headers: {
              'X-Forwarded-Proto': 'https',
              Host: domain,
            },
          }, {concurrency: 2}));
        });

we got a new error RequestError: options.retry.calculateDelay is not a function

@szmarczak sorry if I m not very clear :-/

zckrs avatar Oct 08 '21 08:10 zckrs

Can't reproduce:

import got from 'got';

try {
    const response = await got('http://httpbingo.org/status/500', { method: 'CUSTOM', responseType: 'text', retry: { limit: 1 } });
    console.log(response.retryCount);
} catch (error) {
    console.log(error.response.retryCount);
}

szmarczak avatar Dec 10 '21 17:12 szmarczak