Apollo-client-devtools: Uncaught DOMException: Failed to execute 'postMessage' on 'Window' #1879

Created on 17 Jul 2017  路  21Comments  路  Source: apollographql/apollo-client-devtools

From AC

  • could be related to #1871

I have afterware on my apollo client to handle errors in my app. In order to check the server's response status I have to clone the response. It was working fine until suddenly (chrome update?) I started getting this message:
DOMException: Failed to execute 'postMessage' on 'Window': Error: Network request failed with status 401 - "Unauthorized" could not be cloned.
(the error is the response from the server).

To replicate, create an afterware that clones the response from the server.

Thanks!

Most helpful comment

Guys, I found a solution! Disable Apollo-client-devtools and viola, no more junk spewed into the console...haha. But seriously, hugely annoying bug -- I'm disabling it until this is fixed.

All 21 comments

Are you trying to post objects that are not Json-serializable? If so, this is the same issue as #58

Ah! Maybe this error has to do with errors being displayed in the dev tools?

Hitting this error as well. Does anyone have an idea why having an afterware with response.clone() would be causing this to occur? I don't follow the logic there. Thanks!

VM146910:13 Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'Window': function xhrAdapter(config) {
  return new Promise(function dispatchXhrRequest(resolve, reject) {
    var reque...<omitted>...
} could not be cloned.
    at ApolloClient.hookLogger [as devToolsHookCb] (<anonymous>:13:12)
    at Object.dispatch (http://localhost:4000/static/js/bundle.js:133366:31)
    at dispatch (<anonymous>:2:1620)
...

Also, please let me know if there is anything I can do to help/where to find the actual breaking logic.

Thanks!

@tnrich The breaking is in the hookLogger function defined in hook.js; its because chrome's postMessage function can't handle non-serializable objects. (I think)

@ramyanaga , thanks for the info!

Just to be clear, you're referring to this line in particular

  const newStateData = {
      queries: logItem.state.queries,
      mutations: logItem.state.mutations,
      inspector: logItem.dataWithOptimisticResults
    }
    window.postMessage({ newStateData }, '*');

https://github.com/apollographql/apollo-client-devtools/blob/master/extension/hook.js#L27

That's what looked like the culprit might be to me as well. Is there something simple we could do to provide better feedback to the user? Perhaps something like:

    try {
        JSON.stringify({newStateData})
    } catch (e) {
        return console.error('Uh oh, an error occurred when trying to serialize your apollo data:', e)
        //ideally we could make this message show up to the user so they know what is going wrong when serializing and can fix that error?
    }
    const newStateData = {
      queries: logItem.state.queries,
      mutations: logItem.state.mutations,
      inspector: logItem.dataWithOptimisticResults
    }
    window.postMessage({ newStateData }, '*');

@tnrich yep that's the line in particular. I'll try adding that line to give better error messages, but ideally I'd just stringify and unstringify the object within the app.
Also, are you running the most recent version of the devtools (2.0.2)? I created a test app that uses response.clone() in afterware, but I don't seem to be having a problem

@ramyanaga , Yes I am using the latest version of the devtools, but I commented out the response.clone() line and I am still hitting this issue so it must be coming from something else. I was just confused initially and saw the .clone() in the error message and thought that my call was causing it.

@ramyanaga Also, what do you mean by

but ideally I'd just stringify and unstringify the object within the app.

Where in the app would you be doing that? In the apollo client itself? Or are you saying that as a user I could do a stringify/unstringify myself?

Thanks!

@tnrich So the reason this error is occurring is because the user is including non-serializable objects in their queries (or mutations), which chrome's postMessage function cannot handle. For example, if the user passes in a date, postMesage will throw an error. I'd like to manually serialize this date object, then pass it through the message channels, then convert the data back into a date object before it is displayed on the devtools.

@ramyanaga Cool, thanks for the info!
Are non-serializable objects allowed in graphql queries? I, maybe incorrectly, thought that only json was allowed in graphql queries?

@ramyanaga This is causing a fatal issue in my app whenever we get an error from our GraphQL server (An error where the HTTP response code is 200, but the response contains an errors property). As far as I can tell, the root of the issue is that ApolloClient dispatches [1] an instance of Error (since ApolloError extends Error [2]) to Redux. Error objects are not able to be sent via window.postMessage [3]. I don't believe there is anything I can do on the app side to prevent or solve this other than to not use the Apollo DevTools.

@peisenmann Thanks for the info. Can you reproduce the error for us or give us a way of reproducing it (using a site like Githunt). I'll look into it more and see if there's a way we can convert Errors to JSON before sending them through window.postMessage

Hey guys, I am also experiencing this issue when sending encoded json as a string.

Request payload:

{
    "operationName": "submitQuestionnaire",
    "query": "mutation submitQuestionnaire($questionnaireId: Int!, $answers: [ParticipantAnswerInputType]!, $demographicAnswers: [DemographicParticipantAnswer]!) {\n  submitQuestionnaire(questionnaireId: $questionnaireId, answers: $answers, demographicAnswers: $demographicAnswers)\n}\n",
    "variables": {
        "answers": [
            {
                "questionId": 1,
                "timeout": false,
                "value": "1"
            },
            {
                "questionId": 2,
                "timeout": false,
                "value": "1"
            },
            {
                "questionId": 3,
                "timeout": false,
                "value": "2"
            },
            {
                "questionId": 4,
                "timeout": false,
                "value": "1"
            },
            {
                "questionId": 5,
                "timeout": false,
                "value": "\"PLUS\""
            },
            {
                "questionId": 6,
                "timeout": false,
                "value": "\"MINUS\""
            },
            {
                "questionId": 7,
                "timeout": false,
                "value": "\"PLUS_PLUS\""
            },
            {
                "questionId": 8,
                "timeout": false,
                "value": "\"MINUS_MINUS\""
            },
            {
                "questionId": 9,
                "timeout": false,
                "value": "1"
            },
            {
                "questionId": 10,
                "timeout": false,
                "value": "2"
            },
            {
                "questionId": 11,
                "timeout": false,
                "value": "1"
            },
            {
                "questionId": 12,
                "timeout": false,
                "value": "2"
            },
            {
                "questionId": 13,
                "timeout": false,
                "value": "\"MINUS_MINUS\""
            },
            {
                "questionId": 14,
                "timeout": false,
                "value": "\"PLUS_PLUS\""
            },
            {
                "questionId": 15,
                "timeout": false,
                "value": "\"PLUS\""
            },
            {
                "questionId": 16,
                "timeout": false,
                "value": "\"MINUS\""
            }
        ],
        "demographicAnswers": [],
        "questionnaireId": 1
    }
}

Relevant types:

type ParticipantAnswerInputType {
  questionId: Int!
  timeout: Boolean!
  value: String! # Processed with JSON.stringify
}

type DemographicParticipantAnswer {
  demographicElementId: Int!
  value: String! # Processed with JSON.stringify
}

Error Messages:

DOMException: Failed to execute 'postMessage' on 'Window': function ROOT() {} could not be cloned.
    at ApolloClient.hookLogger [as devToolsHookCb] (<anonymous>:20:14)
    at http://localhost:4202/assets/vendor.js:86772:27
    at Object.dispatch (http://localhost:4202/assets/vendor.js:78180:16)
    at QueryManager.mutate (http://localhost:4202/assets/vendor.js:86942:20)
    at ApolloClient.mutate (http://localhost:4202/assets/vendor.js:86730:34)
    at http://localhost:4202/assets/vendor.js:119155:22
    at initializePromise (http://localhost:4202/assets/vendor.js:68589:7)
    at new Promise (http://localhost:4202/assets/vendor.js:69073:33)
    at Class.mutate (http://localhost:4202/assets/vendor.js:119154:28)
    at Class.mutate (http://localhost:4202/assets/sum.bundle.js:113:27)

DOMException: Failed to execute 'postMessage' on 'Window': function ROOT() {} could not be cloned.
    at ApolloClient.hookLogger [as devToolsHookCb] (<anonymous>:20:14)
    at http://localhost:4202/assets/vendor.js:86772:27
    at Object.dispatch (http://localhost:4202/assets/vendor.js:78180:16)
    at http://localhost:4202/assets/vendor.js:86970:29
    at <anonymous>

The "JSON" field are stringified before so AFAIK this should not have any custom behaviour. I will try to set up a reproduction repo.

The issue was a non-serializable array (which was provided by Ember). I fixed the issue by converting it to a "plain" array before passing it into the mutation.

Same here, this is my resolver with apollo server and mongoose

signUp: async (parent, args, { models }) => {
      const user = args
      user.contrasena = await bcrypt.hash(user.contrasena, 12)
      try {
        const newUser = await new models.User(user).save()
        return newUser
      } catch (error) {
        if (error.message.includes('users.$cedula_1 dup key')) {
          throw new Error('La c茅dula ingresada ya est谩 registrada')
        } else if (error.message.includes('users.$email_1 dup key')) {
          throw new Error('El email ingresado ya est谩 registrado')
        } else {
          throw new Error(error.message)
        }
      }
    }

And this is the error I'm getting in the console when committing an action with vuex:

DOMException: Failed to execute 'postMessage' on 'Window': Error: GraphQL error: La c茅dula ingresada ya est谩 registrada could not be cloned.
    at ApolloClient.hookLogger [as devToolsHookCb] (<anonymous>:20:14)
    at eval (webpack-internal:///242:250:27)
    at Object.eval [as dispatch] (webpack-internal:///110:23:16)
    at QueryManager.mutate (webpack-internal:///243:133:20)
    at ApolloClient.mutate (webpack-internal:///242:208:34)
    at signUp (webpack-internal:///260:72:75)
    at Array.wrappedActionHandler (webpack-internal:///613:603:15)
    at Store.dispatch (webpack-internal:///613:346:15)
    at Store.boundDispatch [as dispatch] (webpack-internal:///613:271:21)
    at eval (webpack-internal:///629:55:25)
VM4608:23 DOMException: Failed to execute 'postMessage' on 'Window': Error: GraphQL error: La c茅dula ingresada ya est谩 registrada could not be cloned.
    at ApolloClient.hookLogger [as devToolsHookCb] (<anonymous>:20:14)
    at eval (webpack-internal:///242:250:27)
    at Object.eval [as dispatch] (webpack-internal:///110:23:16)
    at eval (webpack-internal:///243:154:33)
    at <anonymous>
index.js?e3b1:77 Error: GraphQL error: La c茅dula ingresada ya est谩 registrada
    at new ApolloError (ApolloError.js?d743:34)
    at eval (QueryManager.js?2cbe:129)
    at <anonymous>

Guys, I found a solution! Disable Apollo-client-devtools and viola, no more junk spewed into the console...haha. But seriously, hugely annoying bug -- I'm disabling it until this is fixed.

Something similar happens to me without using an afterware: I get this error:

DOMException: Failed to execute 'postMessage' on 'Window': TypeError: Cannot add property nodes, object is not extensible could not be cloned.

...when using apollo-link-state as only addition:

const httpLink = createHttpLink({ uri: 'http://localhost:5000/graphql' })
const client = new ApolloClient({
  link: concat(localStateLink, httpLink),
  cache: new InMemoryCache(),
})

And it only seems to happen in an (unsolved) case where apollo returns this error:

Network error: Cannot add property nodes, object is not extensible

Disabling devtools removes the DOMException but not the network error (that probably causes the DOMException ).

Just getting plugged into this thread for updates on this issue, which I'm also experiencing.

@loganpowell there is a button on top right for that: Notifications: "unsuscribe" (it was named "subscribe" before your comment)

@barbalex but then I couldn't get nice messages like yours

I'm going to close this issue up because it hasn't seen any activity in over a year. If anyone is still seeing an issue, please re-open the issue. Thank you!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stubailo picture stubailo  路  4Comments

mvestergaard picture mvestergaard  路  6Comments

kissu picture kissu  路  4Comments

jeffdesign picture jeffdesign  路  5Comments

rogue-agent picture rogue-agent  路  3Comments