Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DevTools: Failed to execute 'postMessage' on 'Window': #<HTMLAllCollection> could not be cloned. #16691

Closed
jimniels opened this issue Sep 6, 2019 · 25 comments · Fixed by #19619

Comments

@jimniels
Copy link

jimniels commented Sep 6, 2019

Do you want to request a feature or report a bug?

Report a bug.

What is the current behavior?

New dev tools are working fine. But I have a particular component that, when it mounts, the dev tools no longer can inspect anything about it. When I select it, the right hand side just says "Loading..." and nothing ever loads.

interactive

As you can see from the gif above, before I click on that particular component that seems to break, I have no errors in my console. But as soon as I click on the component that breaks (or any of its children) the number of console errors goes up by one.

The error in the console looks like this:

Screen Shot 2019-09-06 at 4 08 14 PM

backend.js:1 Uncaught DOMException: Failed to execute 'postMessage' on 'Window': #<HTMLAllCollection> could not be cloned.
    at Object.send (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/backend.js:1:94424)
    at chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/backend.js:9:5785

Hard to provide steps to reproduce this since it's a custom component with business-specific logic (so can't provide the code). But I tried google-ing this problem and error and nothing showed up. So figured posting it here might help if others out there on the interwebs are having the same issue and they can comment here.

What is the expected behavior?

Inspecting any mounted component will work.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

Currently on react/react-dom 16.3 and the previous dev tools worked just fine. I could inspect any component and see it's data. But the latestest update broke that.

@jimniels jimniels changed the title Bug: Failed to execute 'postMessage' on 'Window': #<HTMLAllCollection> could not be cloned. DevTools: Failed to execute 'postMessage' on 'Window': #<HTMLAllCollection> could not be cloned. Sep 6, 2019
@bvaughn
Copy link
Contributor

bvaughn commented Sep 7, 2019

Hard to provide steps to reproduce this since it's a custom component with business-specific logic (so can't provide the code).

Should be sufficient to supply a small app that uses a component with whatever prop/state is causing the error. (Shouldn't need the surrounding app or complexity.)

@jimniels
Copy link
Author

jimniels commented Sep 7, 2019

To be honest I’m not sure where to begin. The component that’s causing the error is the root component of an internal library. And I can’t see inside the component for its props/state and look for irregularities because the devtools don’t work. And the error message doesn’t clue me into where this could be an issue. So I’m not sure where to start troubleshooting.

Was hoping by posting here others might find the issue and be in a situation to provide more insight. Otherwise, when I find time, I could maybe just start trying to strip out props one by one and see if I can get it working.

@Jessidhia
Copy link
Contributor

HTMLAllCollection looks incredibly fishy. Does that custom component hold a reference to document or window somewhere (props or state), or worse, a reference to document.all?

@zhang123ming

This comment has been minimized.

@zhang123ming

This comment has been minimized.

@jimniels
Copy link
Author

jimniels commented Sep 9, 2019

@Jessidhia good question. It does in fact hold a couple references to window but I was able to hunt down the issue and it doesn't appear directly related to those particular usage contexts.


The Problem

So it appears the issue stems from a part of the code that is saving an XMLDocument in the component state. That is what is breaking the devtools. The component is getting an XML string from the server and then it is parsing that XML string using window.DOMParser().parseFromString() and storing the result in the state of the component as an XMLDocument. This is what breaks the devtools.

Here's an example:

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // If you comment this out, the devtools work
      // If you leave it it, the devtools break
      dom: new window.DOMParser().parseFromString(
        `<Candy type="snickers"></Candy>`,
        "application/xml"
      )
    };
  }

  render() {
    return <div>Test</div>;
  }
}

I put this example on codesandbox where you can test this out yourself. If you comment out the where the result of window.DOMParser.parseFromString() is being stored in the component state, the devtools work. If you leave it in, the devtools break (as I initially described).

@bvaughn bvaughn self-assigned this Sep 9, 2019
@bvaughn
Copy link
Contributor

bvaughn commented Sep 9, 2019

Currently on react/react-dom 16.3 and the previous dev tools worked just fine.

I don't think this is accurate? So far as I'm aware, v3 would have also failed to serialize this type of value, and a quick test using Code Sandbox and the latest version of v3 seems to confirm this.

@bvaughn
Copy link
Contributor

bvaughn commented Sep 9, 2019

I'm not sure of a way to detect this type other than e.g. HTMLAllCollection.prototype.isPrototypeOf(thing) - but I don't think that would work in the case of frames.

Maybe we could check e.g. thing !== undefined && typeof thing === 'undefined' && thing.toString() === "[object HTMLAllCollection]" but that seems really sketchy in a few ways.

@bvaughn bvaughn removed their assignment Sep 9, 2019
@jimniels
Copy link
Author

jimniels commented Sep 9, 2019

I don't think this is accurate? So far as I'm aware, v3 would have also failed to serialize this type of value

I could've sworn it worked for me. So I installed an old version (3.5.0) and loaded up my component and it worked just fine. I could inspect the entire tree and see all my state/props. The XML dom showed up in the devtools like so:

Screen Shot 2019-09-09 at 4 58 15 PM

a quick test using Code Sandbox and the latest version of v3

I also loaded up my example in the codesandbox and devtools v3.5.0 appear to work just fine. You can see the type XMLDocument show up next to the state

Screen Shot 2019-09-09 at 4 58 53 PM

So, at least on my machine, it is/was working on v3.

@gaearon
Copy link
Collaborator

gaearon commented Sep 10, 2019

Before we try to detect it — do we understand what actually causes the error? What code is trying to “clone” it?

@aweary
Copy link
Contributor

aweary commented Sep 10, 2019

I'm guessing it's because devtools uses window.postMessage to communicate across the bridge and postMessage uses the structured cloning algorithm.

@aweary
Copy link
Contributor

aweary commented Sep 10, 2019

It's suspicious that the error is reporting HTMLAllCollection, because if the XML document was the actual problem it would report that XMLDocument could not be cloned.

window.postMessage(
  new window.DOMParser().parseFromString(
    `<Candy type="snickers"></Candy>`,
    "application/xml"
  )
);
VM640:1 Uncaught DOMException: Failed to execute 'postMessage' on 'Window': XMLDocument object could not be cloned.
    at <anonymous>:1:8

@aweary
Copy link
Contributor

aweary commented Sep 10, 2019

It looks like this is due to how the backend identifies data types for serializing across the bridge. The getDataType check is returning "object" for the XMLDocument, which then means the backend attempts to recursively create a regular object to send across the bridge. This ends up returning a regular object that holds a reference to document.all which is what ends up failing.

I'm betting the logic isn't handling the weird document.all semantics, so it's not catching that it's passing through a value that cannot be cloned.

@gaearon
Copy link
Collaborator

gaearon commented Sep 10, 2019

I think what’s happening here is:

  1. document.all !== null and document.all !== undefined
  2. However typeof document.all === "undefined"
  3. As a result its “data type” as determined by getDataType is "unknown"
  4. The switch in dehydration falls through to the default case (no case for unknown types) which just does return data

If this analysis is right, the fix would be to either add a special type for document.all, or to have getDataType treat it as an object (despite its exotic typeof). Or maybe treat it as if it doesn’t exist.

@Jessidhia
Copy link
Contributor

document.all is the only value which is !== null, !== undefined, and also == null. Perhaps this apparent contradiction can be used to check it. Or the fact that it's !== undefined but its typeof is 'undefined'.

This is the specification for its behavior btw, unsurprisingly in Annex B: https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot

@gaearon
Copy link
Collaborator

gaearon commented Sep 10, 2019

Or the fact that it's !== undefined but its typeof is 'undefined'.

Yep, that’s what I meant above. This causes getDataType to return "unknown" and then causes dehydration to fall into the default branch.

@bvaughn
Copy link
Contributor

bvaughn commented Sep 10, 2019

I also loaded up my example in the codesandbox and devtools v3.5.0 appear to work just fine. You can see the type XMLDocument show up next to the state

document.all is of type HTMLAllCollection, which is different from XMLDocument. For my test case, I was just passing document.all as a prop to a component and both v3 and v4 error in the same way in this case.

But yes, Dan's right in that the unexpected typeof for HTMLAllCollection confuses the backend.

@epotockiy
Copy link

epotockiy commented Sep 24, 2019

Today I ran into the same problem, but i didn't have any xml document parts in my code or props. This issue happens at random and don't stop until I close browser tab (reload didn't help) or reload extension

backend.js:6 Uncaught DOMException: Failed to execute 'postMessage' on 'Window': #<HTMLAllCollection> could not be cloned.
    at Object.send (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/backend.js:6:75756)
    at chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/backend.js:30:8471
send @ backend.js:6
(anonymous) @ backend.js:30
setTimeout (async)
value @ backend.js:30
i @ backend.js:6

@drochette
Copy link

Any news about a fix ?

@adamdva
Copy link

adamdva commented Dec 18, 2019

Any news about a fix ? Making devtools unusable on my app

@gaearon
Copy link
Collaborator

gaearon commented Dec 18, 2019

If there were news about a fix, you would see them on this thread.
Do you want to send a fix?

@bvaughn
Copy link
Contributor

bvaughn commented Dec 18, 2019

@adamdva If you could provide a small repro case that captures this behavior, that would also be helpful.

@omarsy
Copy link
Contributor

omarsy commented Aug 11, 2020

Can I take this one ?

@bvaughn
Copy link
Contributor

bvaughn commented Aug 11, 2020

@omarsy If you'd like to look into this issue, please feel free.

@Ayc0
Copy link

Ayc0 commented Aug 12, 2020

I was able to reproduce here: https://hzw2k.csb.app/

image

Source code: https://codesandbox.io/s/react-devtools-error-hzw2k?file=/src/App.js:214-250

this is obviously a silly code but that reflects a bit something that I have in my app (a dynamic ref that can set to document for global event listeners)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.