Apollo-module: Cannot stringify POJOs with symbolic keys on nuxt 2

Created on 1 Oct 2018  Â·  15Comments  Â·  Source: nuxt-community/apollo-module

Version

v4.0.0-rc.2

Reproduction link

https://github.com/nuxt-community/apollo-module

Steps to reproduce

I get this error after update nuxt 2.0.0 to 2.1.0, revert back to 2.0.0 still geting the problem. It's happen on my both 2 project when return the value that query by apollo in asyncData:

  async asyncData({ error, app, params }){
    const post = await app.apolloProvider.defaultClient.query({
      query: postQuery,
      variables: { slug: params.slug }
    }).then(({ data }) => data && data.post)

    if (!post) return error({ statusCode: 404, message: 'Not found!!' })

    return { post }
  },

Nuxt 1.4.2 is working normally, anyone have the same problem? Another weird thing, on codesanbox, nuxt 2.1.0 still working.

What is expected ?

Shouldn't get error.

What is actually happening?

Getting error.

This bug report is available on Nuxt community (#c145)
bug-report

Most helpful comment

I ran into this error this morning when attempting to upgrade to Nuxt 2.1. After some investigating, I was able to get it to work by cloning the Apollo response. I typically do this anyway due to how Apollo returns data as read-only, but this one particular page returning the error was one area I wasn't cloning. Here's an example:

Throws error in Nuxt 2.1:

let client = app.apolloProvider.defaultClient
try {
  let { data } = await client.query({ query: USER_QUERY })
  Object.assign(store.state.user, data.user)
} catch (err) {
  // handle error
}

Works in Nuxt 2.1:

Object.assign(store.state.user, _.clone(data.user))

Note: lodash is used here, but there are other ways to "clone" responses worth investigating for your wants/needs.

I haven't yet diagnosed exactly what causes this, but it seems more to do with Nuxt than it does Apollo (and/or vue-apollo). Rather, it seems Nuxt is using the devalue module; which doesn't like symbolic keys (which happened to be returned from Apollo).

I don't know why/where Nuxt is using the devalue module. I also think it's probably wise for Nuxt to catch the error and throw a warning in this case, rather than letting devalue throw the error uncaught.

_I would exercise caution if Nuxt has systemic issues with read-only or symbolic keys._

If I find out more about this, I'll post back here.

All 15 comments

@kieusonlam apollo-module is currently not prepared for Nuxt v2 yet. There are currently opened issues with vue-apollo and I'm not sure whats the right way to circumvent the current situation. You can follow #158 where I started to upgrade but I'm kind of stuck currently with SSR compatibility. Beside that I also don't have a Nuxt v2 project in place to run. Please feel free to contribute in the PR or open a PR for just for compatibility reasons for v2

@kieusonlam Yes, i got same. Do you know reason for that?

I ran into this error this morning when attempting to upgrade to Nuxt 2.1. After some investigating, I was able to get it to work by cloning the Apollo response. I typically do this anyway due to how Apollo returns data as read-only, but this one particular page returning the error was one area I wasn't cloning. Here's an example:

Throws error in Nuxt 2.1:

let client = app.apolloProvider.defaultClient
try {
  let { data } = await client.query({ query: USER_QUERY })
  Object.assign(store.state.user, data.user)
} catch (err) {
  // handle error
}

Works in Nuxt 2.1:

Object.assign(store.state.user, _.clone(data.user))

Note: lodash is used here, but there are other ways to "clone" responses worth investigating for your wants/needs.

I haven't yet diagnosed exactly what causes this, but it seems more to do with Nuxt than it does Apollo (and/or vue-apollo). Rather, it seems Nuxt is using the devalue module; which doesn't like symbolic keys (which happened to be returned from Apollo).

I don't know why/where Nuxt is using the devalue module. I also think it's probably wise for Nuxt to catch the error and throw a warning in this case, rather than letting devalue throw the error uncaught.

_I would exercise caution if Nuxt has systemic issues with read-only or symbolic keys._

If I find out more about this, I'll post back here.

@bjunc warning is coming instead of error. As for symbolic keys - they wasnt serializing before too, they was just silently ignored. Symbol are not really serializable thing..

Thanks @aldarund. Also nice that you're printing the symbol keys that couldn't be stringified for debugging.

I looked a little bit more into this, and it turns out Apollo uses a symbol for the ID; which I believe is used for internal caching. That means _every_ apollo response will trigger the warning that you've written unless the developer plucks only the serializable data. Since Apollo also sends responses frozen (read-only), I typically use Lodash's clone function anyway. That clone function (similar to the structured clone algorithm) skips symbols and essentially "unfreezes" the response data.

So I think my suggestion to anyone reading this is to clone the apollo response as now a best practice to not only unfreeze the apollo response data, but avoid the devalue warning (which will also avoid the current error before the error-to-warning PR is merged).

I believe this has no connection with apollo. Using this code throws the same error:

  async asyncData({params}) {
    const fileContent = await import(`~/static/content/${params.slug}.md`)

    return {
      content: fileContent,
    }
  },

throws:

✖ error NuxtServerError: Cannot stringify POJOs with symbolic keys
  at walk (/Users/davidlicen/Documents/Projects/0xcert/landing-www/node_modules/devalue/dist/devalue.umd.js:47:31)
  at /Users/davidlicen/Documents/Projects/0xcert/landing-www/node_modules/devalue/dist/devalue.umd.js:49:72
  at Array.forEach (<anonymous>)
  at walk (/Users/davidlicen/Documents/Projects/0xcert/landing-www/node_modules/devalue/dist/devalue.umd.js:49:40)
  at Array.forEach (<anonymous>)
  at walk (/Users/davidlicen/Documents/Projects/0xcert/landing-www/node_modules/devalue/dist/devalue.umd.js:33:27)
  at /Users/davidlicen/Documents/Projects/0xcert/landing-www/node_modules/devalue/dist/devalue.umd.js:49:72
  at Array.forEach (<anonymous>)
  at walk (/Users/davidlicen/Documents/Projects/0xcert/landing-www/node_modules/devalue/dist/devalue.umd.js:49:40)
  at devalue (/Users/davidlicen/Documents/Projects/0xcert/landing-www/node_modules/devalue/dist/devalue.umd.js:53:5)
  at Renderer.renderRoute (/Users/davidlicen/Documents/Projects/0xcert/landing-www/node_modules/nuxt/dist/nuxt.js:2042:50)
  at <anonymous>

Using Nuxt 2.1

@davision per above, this error has more to do with the devalue module not like Symbol keys; which Apollo happens to use. I don't know what is returned from your example, but there's likely a Symbol in there. You can check by:

Object.getOwnPropertySymbols(fileContent)

@bjunc I tried your above code but for me the symbols are not removed through lodash.clone:

        const article = _clone(data) // this is from a query response of apollo
        console.log('article:', Object.getOwnPropertySymbols(article)) // => article: [ Symbol(id) ]

Any idea how to remove the symbols?

@dohomi, I believe the above should work. However, _.clone() is shallow, so if your article has nested objects, they too will have symbols for the ID. Did you try _.cloneDeep()?

@bjunc I realized that somehow lodash.deepclone did not remove the symbols. I changed to clone-deep package and now it works as expected, thanks for the hint.

@dohomi I tried it with v4.0.0-rc.2.2 but still got this error

@AndrewBogdanovTSS where do you see this error? As @bjunc correctly stated, you need to clone/cloneDeep your response inside of asyncData to remove the symbolic keys. This worked for me. I am using https://www.npmjs.com/package/clone-deep to make this work

@dohomi yeah, after I switched to deep-clone in my code it started to work as expected. Thank you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Billybobbonnet picture Billybobbonnet  Â·  4Comments

argueta15 picture argueta15  Â·  6Comments

leviwheatcroft picture leviwheatcroft  Â·  5Comments

drewbaker picture drewbaker  Â·  6Comments

wan2land picture wan2land  Â·  8Comments