apache / couchdb-nano

Nano: The official Apache CouchDB library for Node.js
https://www.npmjs.com/package/nano
Apache License 2.0
651 stars 165 forks source link

scrubLog functionality can fail on JSON circular reference #252

Closed thescrublet closed 3 years ago

thescrublet commented 3 years ago

Consider the following code in relax: ` req.httpAgent = cfg.requestDefaults.agent || defaultHttpAgent req.httpsAgent = cfg.requestDefaults.agent || defaultHttpsAgent

// scrub and log const scrubbedReq = JSON.parse(JSON.stringify(req)) `

I'm having issues where the JSON.stringify can fail due to circular references in Socket. Traditionally I've avoided logging Socket objects in my code because I've run into this problem before.

Expected Behavior

Code functions as designed.

Current Behavior

TypeError: Converting circular structure to JSON --> starting at object with constructor 'Socket' | property '_httpMessage' -> object with constructor 'ClientRequest' --- property 'socket' closes the circle {"timestamp":"2021-01-14T14:13:20.913Z"}

Possible Solution

I believe the scrubLog should happen BEFORE setting the req.httpAgent and req.httpsAgent fields. If you need to get that socket information, debug it.

Steps to Reproduce (for bugs)

I'm still trying to figure out why this happens sometimes and not others. For example, I was getting the error on changesReader.start at one point, but figured out my code was improperly calling the function multiple times. My current code seems fine though: this.myDb.changesReader.start({ includeDocs: true }).on("batch", (batch) => { ... }.on("error", (error) => { console.error(error) }

Context

I'm listening for any event in the database.

Your Environment

glynnbird commented 3 years ago

Thanks for reporting @thescrublet . A fix is on its way through Travis now.

dsebastien commented 3 years ago

It seems like I'm facing a variant of this issue.

The following code works perfectly fine with v8.2.3:

  public ensureThatWorkspaceExists(workspaceId: string): Observable<boolean> {
    this.logger.debug(`Ensuring that the following workspace exists: ${workspaceId}`);
    return defer(() => from(this.databaseConnection.db.list())).pipe(  <----------- seems to crash here
      concatMap((databasesList) => {
            // never gets here
       ...
     }),
    );
  }

In the closest catchError, I get the following error object:

err = TypeError: Converting circular structure to JSON   --> starting at object with constructor 'Socket'    |    property 'parser' -> object with constructor 'HTTPParser' ....
glynnbird commented 3 years ago

Should be fixed in 9.0.3

dsebastien commented 3 years ago

I confirm that it now works perfectly fine again! LGTM! :)

jjd314 commented 3 years ago

If you are using a custom agent in requestDefaults (as described in the docs), the same problem occurs, because the agent is copied directly into the request when it is created.

Dryymoon commented 3 years ago

How to add custom agent:

const agent = new http.Agent();
agent.toJSON = () => null; // This line help bypass Circular json error
const couchdb = require('nano')({
  url: 'http://admin:admin@localhost:5984',
  requestDefaults: {
    agent
  }
});
crystalfp commented 1 year ago

Sorry to reopen this issues, but started happening very frequently in:

dbHandle.view(documentName, viewName, {key: "xxx"})

I don't use agents. The strange thing is that, even if this call is surrounded by try-catch, the exception is catched only by a

process.on("uncaughtException", (ex: Error) => {
    console.error(`Uncaught exception: ${ex.message}\nException origin: ${ex.stack}`);
    process.exit(1);
});

The error printed is:

Uncaught exception: Converting circular structure to JSON
    --> starting at object with constructor 'Socket'
    |     property 'parser' -> object with constructor 'HTTPParser'
    --- property 'socket' closes the circle
Exception origin: TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Socket'
    |     property 'parser' -> object with constructor 'HTTPParser'
    --- property 'socket' closes the circle
    at JSON.stringify (<anonymous>)

Without any clue on where the exception happened. Any idea? I'm running nano 10.1.2 under Node 19.8.1 and couchdb 3.2.2 Thanks! mario