How to debug Ngrok not starting via node module?

Viewed 1607

I'm developing an app that uses Ngrok for dev. Running ngrok from console works:

ngrok http 3011

shows the "console UI" indicating that the tunnel is up and giving me the url to use.

Now I'm trying to setup things so that developers don't need to copy-paste urls etc. But the very basic usage fails for me:

// prepare-server.ts

import ngrok from 'ngrok'
import config from '../config'

(async () => {
    try{
        const nwhUrl = await ngrok.connect({ addr: config.serverPort })
        console.log(nwhUrl)
    } catch(e) {
        console.error('problem with ngrok:', e)
    }
})()

Gives me (when run as ts-node src/prepare-server.ts):

problem with ngrok: NgrokClientError: 
    at NgrokClient.request (<path to project>\node_modules\ngrok\src\client.js:39:23)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)  
    at connectRetry (<path to project>\node_modules\ngrok\index.js:29:22) {
  response: <ref *1> IncomingMessage {
    _readableState: ReadableState {
      objectMode: false,
      highWaterMark: 16384,
      buffer: BufferList { head: null, tail: null, length: 0 },
      length: 0,
      pipes: [],
      flowing: false,
      ended: true,
      endEmitted: true,
      reading: false,
      sync: false,
      needReadable: false,
      emittedReadable: false,
      readableListening: true,
      resumeScheduled: false,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: false,
      destroyed: false,
      errored: false,
      closed: false,
      closeEmitted: false,
      defaultEncoding: 'utf8',
      awaitDrainWriters: null,
      multiAwaitDrain: false,
      readingMore: false,
      decoder: [StringDecoder],
      encoding: 'utf8',
      [Symbol(kPaused)]: null
    },
    _events: [Object: null prototype] {
      end: [Array],
      aborted: [Array],
      error: [Array],
      readable: [Array],
      finish: [Function: onfinish],
      close: [Function: onclose]
    },
    _eventsCount: 6,
    _maxListeners: undefined,
    socket: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: null,
      _server: null,
      parser: null,
      _httpMessage: [ClientRequest],
      _peername: [Object],
      [Symbol(asyncId)]: 15,
      [Symbol(kHandle)]: [TCP],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0
    },
    httpVersionMajor: 1,
    httpVersionMinor: 1,
    httpVersion: '1.1',
    complete: true,
    headers: {
      'content-type': 'application/json',
      date: 'Wed, 21 Jul 2021 10:14:40 GMT',
      'content-length': '168',
      connection: 'close'
    },
    rawHeaders: [
      'Content-Type',
      'application/json',
      'Date',
      'Wed, 21 Jul 2021 10:14:40 GMT',
      'Content-Length',
      '168',
      'Connection',
      'close'
    ],
    trailers: {},
    rawTrailers: [],
    aborted: false,
    upgrade: false,
    url: 'http://127.0.0.1:4041/api/tunnels',
    method: null,
    statusCode: 503,
    statusMessage: 'Service Unavailable',
    client: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: null,
      _server: null,
      parser: null,
      _httpMessage: [ClientRequest],
      _peername: [Object],
      [Symbol(asyncId)]: 15,
      [Symbol(kHandle)]: [TCP],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0
    },
    _consuming: true,
    _dumped: false,
    req: ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 10,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: null,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      socket: [Socket],
      _header: 'POST /api/tunnels HTTP/1.1\r\n' +
        'user-agent: got (https://github.com/sindresorhus/got)\r\n' +    
        'content-type: application/json\r\n' +
        'accept: application/json\r\n' +
        'content-length: 74\r\n' +
        'accept-encoding: gzip, deflate, br\r\n' +
        'Host: 127.0.0.1:4041\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _onPendingData: [Function: noopPendingOutput],
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/api/tunnels',
      _ended: true,
      res: [Circular *1],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      timings: [Object],
      emit: [Function (anonymous)],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(reentry)]: true
    },
    timings: {
      start: 1626862480674,
      socket: 1626862480676,
      lookup: 1626862480677,
      connect: 1626862480677,
      secureConnect: undefined,
      upload: 1626862480677,
      response: 1626862480678,
      end: 1626862480680,
      error: undefined,
      abort: undefined,
      phases: [Object]
    },
    emit: [Function (anonymous)],
    requestUrl: 'http://127.0.0.1:4041/api/tunnels',
    redirectUrls: [],
    request: Request {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 16,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      requestInitialized: true,
      redirects: [],
      retryCount: 0,
      _progressCallbacks: [],
      write: [Function: onLockedWrite],
      end: [Function: onLockedWrite],
      options: [Object],
      requestUrl: 'http://127.0.0.1:4041/api/tunnels',
      _cannotHaveBody: false,
      _noPipe: true,
      [Symbol(kCapture)]: false,
      [Symbol(downloadedSize)]: 168,
      [Symbol(uploadedSize)]: 74,
      [Symbol(serverResponsesPiped)]: Set(0) {},
      [Symbol(stopReading)]: true,
      [Symbol(triggerRead)]: false,
      [Symbol(jobs)]: [],
      [Symbol(body)]: '{"addr":3011,"proto":"http","name":"2fbfea07-1dc3-4d7b-acfc-20a68b755c10"}',
      [Symbol(bodySize)]: 74,
      [Symbol(cancelTimeouts)]: [Function: cancelTimeouts],
      [Symbol(unproxyEvents)]: [Function (anonymous)],
      [Symbol(request)]: [ClientRequest],
      [Symbol(originalResponse)]: [Circular *1],
      [Symbol(isFromCache)]: false,
      [Symbol(responseSize)]: 168,
      [Symbol(response)]: [Circular *1],
      [Symbol(startedReading)]: true
    },
    isFromCache: false,
    ip: '127.0.0.1',
    retryCount: 0,
    rawBody: <Buffer >,
    body: '',
    [Symbol(kCapture)]: false
  },
  body: ''
}

Note the 503 Service Unavailable code. How so if the CLI version works?

Any ideas how to debug this? I've also tried this without options (await ngrok.connect()) and the output doesn't change much. And this is an absolutely basic example (see docs), so I can't really do more to simplify the code, looks like something about Ngrok internals... Node package is v4.0.1

PS this issue is probably related or the same. While my problem takes place for Node 14.1.0, it's doesn't take place for Node 15.14.0.

1 Answers

Given the details you have provided, this seems like it was an internal ngork bug or some obscure incompatibility with some specific node versions.

Trying newer (or sometimes even older!) versions of packages and/or node is actually not too hard and might help shed light on the nature of the issue if not solving it entirely (as it happened in your case).

The best thing you could have done IMO in case updating did not fix the issue would be to open an issue on their Github repo since it seems the issue was deep enough in the ngork internal working that I would not expect many people being able to help.

https://github.com/bubenshchykov/ngrok/issues

Related