Node: ES6 ${} causing an Uncaught TypeError: Cannot convert object to primitive value

Created on 19 Mar 2018  路  4Comments  路  Source: nodejs/node

  • Version: 9.4.0
  • Platform: macOs 10.13.1
  • Subsystem:

I was running a simple nodejs server, using nodejs url module to parse request.url.
After sending request to this server, the interpreter threw error in the place where a parsed query object embraced by ES6 ${} is supposed to be logged.

const http = require('http')
const url = require('url')
// let port = process.argv[2]

let port = 9000
const server = http.createServer()
server.listen(port)

server.on('request', (request, response) => {

    let requestUrl = require('url').parse(request.url, true)

    let path = requestUrl.path
    let query = requestUrl.query

    // console.log(`path: ${path}`)
    // console.log('requestUrl: ',requestUrl)

    console.log(`querytype: ${typeof query}`)
    console.log(`query: ${JSON.stringify(query)}`)
    // this will throw error: console.log(`query: ${query}`)
    // this won't throw error : console.log(query)


    response.statusCode = 200
    response.end('')
})
feature request url

Most helpful comment

This is correct behavior, passing an object to console.log does not simply convert the object into a string, when you call console.log(someValue) in Node console.log will internally try to create a representation.

On the flip side when you use `${ someObject }` JavaScript itself will attempt to convert it into a string using the Symbol.toPrimitive method if it exists, otherwise it will attempt to call .toString on the object.

Now if neither [Symbol.toPrimitive] or .toString exist then you'll get the TypeError: Cannot convert object to primitive value. This might be surprising as `${ { x: 10 } }` produces "[object Object]", but that's because Object.getPrototypeOf({ x: 10 }) === Object.prototype which has a .toString method.

The object in requestUrl.query has null prototype (Object.getPrototypeOf(requestUrl.query) === null) hence it doesn't get the .toString method like regular objects do. As such String(requestUrl.query)/"" + requestUrl.query/`${ requestUrl.query }` all throw an error.

All 4 comments

It seems this is because query has null as a prototype, so it has not .toString() method called by the template strings:

const obj = Object.create(null);
obj.foo = 'bar';

console.log(`${obj}`); // TypeError: Cannot convert object to primitive value
const obj = Object.create(null);
obj.foo = 'bar';

obj.toString = function () { return JSON.stringify(this); };

console.log(`${obj}`); // {"foo":"bar"}

This is correct behavior, passing an object to console.log does not simply convert the object into a string, when you call console.log(someValue) in Node console.log will internally try to create a representation.

On the flip side when you use `${ someObject }` JavaScript itself will attempt to convert it into a string using the Symbol.toPrimitive method if it exists, otherwise it will attempt to call .toString on the object.

Now if neither [Symbol.toPrimitive] or .toString exist then you'll get the TypeError: Cannot convert object to primitive value. This might be surprising as `${ { x: 10 } }` produces "[object Object]", but that's because Object.getPrototypeOf({ x: 10 }) === Object.prototype which has a .toString method.

The object in requestUrl.query has null prototype (Object.getPrototypeOf(requestUrl.query) === null) hence it doesn't get the .toString method like regular objects do. As such String(requestUrl.query)/"" + requestUrl.query/`${ requestUrl.query }` all throw an error.

Perhaps a good course of action is to add a @@toPrimitive to the dictionary object? I.e.:

this.query[Symbol.toPrimitive] = function() { return querystring.stringify(this); }

@vsemozhetbyt @Jamesernator @bnoordhuis
Thank you all for your information, this helped me understanding how ${} works.
BTW if there's anyone else run into the same issue here's querystring source code

function parse(qs, sep, eq, options) {
  const obj = Object.create(null);
...
  return obj;
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

feross picture feross  路  208Comments

speakeasypuncture picture speakeasypuncture  路  152Comments

yury-s picture yury-s  路  89Comments

VanCoding picture VanCoding  路  204Comments

mikeal picture mikeal  路  90Comments