sveltejs / svelte

Cybernetically enhanced web apps

Home Page:https://svelte.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Uncaught (in promise) TypeError: Cannot read property 'removeChild' of null

burningTyger opened this issue · comments

I couldn't reproduce the error in the repl and I also can't post the data since it is confidential.
I'll try to post as much information as possible though.

This is the component:

  {#each schueler as s (s.ID)}
    {#each s.abschnitte.filter(aktJahr) as a (a.ID)}
        <Voffset/>{a.Jahr}
    {/each}
  {/each}

<script>
  import Voffset from './partials/Voffset.html'
  // the file looks like this
  // ./partials/Voffset.html
  // <div></div>

  export let jahr, schueler
  // schueler looks like this just way more complex and about 1MB in size
  // schueler = [{abschnitte: [{Jahr: 2017},{Jahr: 2018}]}, {abschnitte: [{Jahr: 2017},{Jahr: 2018}]}]
  $: aktJahr = a => a.Jahr === jahr
</script>
svelte = new Component({ target: document.querySelector('svelte'), props })

this works just fine.

later on when I change some props I do it like this:

svelte.$set({ jahr: abschnitt.jahr, abschnitt: abschnitt.abschnitt })

sometimes it works, sometimes not. It renders the component but then fails and I can't change the data again.

This is the error message:

internal.mjs:111 Uncaught (in promise) TypeError: Cannot read property 'removeChild' of null
    at detachNode (VM110 bundle.js:113)
    at Object.destroy [as d] (VM110 bundle.js:1555)
    at destroyBlock (VM110 bundle.js:1006)
    at on_outro (VM110 bundle.js:1012)
    at run (VM110 bundle.js:23)
    at Array.forEach (<anonymous>)
    at run_all (VM110 bundle.js:31)
    at check_outros (VM110 bundle.js:535)
    at Object.update [as p] (VM110 bundle.js:1675)
    at update (VM110 bundle.js:937)

this seems to only happen with two nested loops and the imported component.

A very simple and well working workaround (not even a speed penalty so far) seems to be a destroy() and recreation of the component. Should have tried that earlier than setting the data.

I have also encountered this, but cannot reproduce at the moment. It went usually like this:

  1. Visit /items
  2. Click link to /items/[id]/specific (happens to be a sapper app)
  3. Click link to /items
    => empty page and console shows: TypeError: Cannot read property 'removeChild' of null
commented

Same issue is happening to me while using Sapper when navigating randomly. Very hard to reproduce but it happens often enough for it to be a problem.

I've also seen it happen when some library replaced DOM objects leaving it in a state that svelte is confused about. My temp fix is to change line 130 of node_modules/svelte/internal.mjs to:

function detach(node) {
	if(node.parentNode) {
		node.parentNode.removeChild(node);
	}
}

UPDATE: in the latest version this is located at line 181.

I was having the same exact issue while working with <svelte:component> used alongside <svelte:window on:hashchange>. It was working fine until the components I was loading dynamically were using katex. The fix mentioned by @ciri worked. Currently I'm using patch-package on npm to apply the patch until it is fixed.

this is happening to me when I am using a hashchange event as well (not sure if that's the reason or not, but since someone else mentioned it)

I am using an array that has values, then on a hash change, a filter is applied. Whenever that filter comes up with an empty array as the result, when there was something in the array to begin with, then this error seems to happen for me.

assume item => false is a filter function that ends up removing all items from the array.

$: filteredItems = items.filter(item => false)

I'm seeing the issue in the same place ciri did.
#2086 (comment)

// first load — remove SSR'd <head> contents
const start = document.querySelector('#sapper-head-start');
const end = document.querySelector('#sapper-head-end');

if (start && end) {
  while (start.nextSibling !== end) detach(start.nextSibling);
  detach(start);
  detach(end);
}

node.nextSibling -

A Node object, representing the next sibling of the node, or null if there is no next sibling

I get error on first load, the detach calls from code above.

Bug when I add description into head.

<svelte:head>
  <title>test</title>
  <description>test</description>
</svelte:head>

My bad, I've added description instead meta tag. Should be

<svelte:head>
  <title>test</title>
  <meta name="description" content="Free Web tutorials">
</svelte:head>

In case it helps -
I had this error as well - I just updated svelte to @3.6.1 and rollup and the accompanying rollup packages (rollup@1.16.2, rollup-plugin-commonjs@10.0.1, rollup-plugin-node-resolve@5.1.
0, rollup-plugin-terser@5.0.0) to their latest and it seems to have gone away.

I started to have this issue (randomly) once I upgraded to version 3.6.x

If anyone can provide a repro, that'd be helpful

This is happening to me when I try to use {#each} in <svelte:head>, in Sapper.

This occurs using sapper when I have a route define a <meta> tag inside of <svelte:head>, then navigate to another route using goto. Having <title>inside of <svelte:head> seems to work.

<script>
	let description = 'foobar'
</script>

<svelte:head>
	<meta name="description" content="{description}"/>
</svelte:head>

This is a hunch, but would it simplify things if src/template.html were src/_template.svelte (a Svelte component) instead?

Since this issue seems to pop up periodically, it would be useful to turn this into a warning. It may not be elegant, but it prevents surprise blank screens due to a navigation error.

function detach(node) {
    if (node && node.parentNode) node.parentNode.removeChild(node);
    else if (node) console.warn('node ' + node + ' is detached. Please submit a bug report.');
    else console.warn('node is falsy. Please submit a bug report.');
}

Seeing this too since 3.6.x (tested good in 3.5.4, bad in 3.6.1). Same as @btakita for me; if I take meta tag definitions out of <svelte:head> then no error. Therefore if you take svelte/realworld, upgrade and add <meta name="description"> to root route and then log-in then I suspect the error will occur.

I forgot to mention in the original issue way back that I have a lot of data. Like 1 to 3 MB that is being passed around via export let foo.

I pushed a hotfix, based on v3.6.3 proposed by #2086 (comment)

In package.json, under devDependencies, use:

"svelte": "btakita/svelte#svelte-gh-2086-hotfix"

I pushed the build files & tested it in my environment so this should work as is.

@btakita your fix works great for me! No errors and the meta updates in the head of each route 😃. Is this fix going to be included in an actual release?

These lines cause the error again when the button is clicked twice: https://gist.github.com/burningTyger/d21f7907820e46ad23bce0b845fb67b9#file-asz-svelte-L64-L79

I couldn't reproduce it in the REPL since this component needs a lot of data and I can't share it.
compiled it looks like this: https://gist.github.com/burningTyger/d21f7907820e46ad23bce0b845fb67b9#file-bundle-js

The error might be of interest too:

VM128 bundle.js:135 Uncaught (in promise) TypeError: Cannot read property 'removeChild' of null
    at detach (VM121 bundle.js:135)
    at Object.destroy [as d] (VM121 bundle.js:2367)
    at outros.callbacks.push (VM121 bundle.js:632)
    at run (VM121 bundle.js:20)
    at Array.forEach (<anonymous>)
    at run_all (VM121 bundle.js:26)
    at check_outros (VM121 bundle.js:615)
    at Object.update [as p] (VM121 bundle.js:3760)
    at update_keyed_each (VM121 bundle.js:955)
    at Object.update [as p] (VM121 bundle.js:3825)

@rwwagner90 I updated another hotfix branch to account for v2.6.5. It's at btakita/svelte#gh-2086-hotfix

There have been some attempts to fix some of the root causes of calling detach when the DOM element is already detached as seen in #3172. However, it's not yet merged due to an issue.

I created a pull request to have the if (node.parentNode) conditional added to detach. It was not applied due to the desire to find the root cause of the <meta> tag manifestation of this issue.

However, IMO, having the conditional in the detach function is necessary, because there are other manifestations of this error. For example, if the DOM element in a component is removed from software outside of svelte, detach will have the same error.

I'm not sure where the core team currently stands on this issue & fix(es). IMO, the conditional needs to be added to detach to fix all manifestations of this error. Ontologically, detach, as an api, should be declarative (ensure the node is detached) instead of imperative (detach the node), allowing it to be called multiple times by performing a noop if the node is already detached. This way, it won't matter if the node is removed from the DOM from outside of svelte.

I'll keep btakita/svelte#gh-2086-hotfix up to date with the latest release in the meantime.

REPRODUCTION here: https://codesandbox.io/s/epic-stonebraker-9cxhu

  • open browser's console
  • click on button "Add random team"
  • wait 3 seconds
  • error in console

Fix by using an intermediate component:

  • open file "Desks.svelte"
  • uncomment on line 12
  • comment on lines from 15 to 23
  • repeat steps from above
  • voilà! it works with no errors!

I tried both with Svelte 3.5.4 and 3.6.5.

@btakita your fix https://github.com/btakita/svelte/tree/gh-2086-hotfix works well for me. It only works if I literally hack the same line intosvelte in my node_modules though (I think that relates to another issue)

I'm still having this issue. Unfortunately, I could not find a way to replicate the issue on the REPL, so here it is in a repo: https://gitlab.com/tohlenforst/issue2086

git clone https://gitlab.com/tohlenforst/issue2086
npm i
npm run dev

Then just click on a link and then try to click a different link.

Can reproduce this error on demand.
Using:
"rollup": "^1.21.2",
"rollup-plugin-commonjs": "^10.0.0",
"rollup-plugin-livereload": "^1.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-scss": "^1.0.2",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^4.0.4",
"svelte": "^3.12.0",
"svelte-material-ui": "^1.0.0-beta.14",
"svelte-routing": "^1.4.0"

svelte-material-ui has a component call 'snackbar'.
This component is modal and has child nodes.
Using this component and then existing the current page (moving to another) provokes this error.

Updating line 145 of 'node_modules/svelte/internal/index.mjs' to
function detach(node) {
if(node.parentNode) {
node.parentNode.removeChild(node);
}
}
steps around the error.

I have also been struggling with this while using a svelte-material-ui List component containing dynamically loaded FontAwesome SVG icons where I could load a list of the icons fine, then load another couple before the following exception is thrown :-

Uncaught (in promise) TypeError: Cannot read property 'removeChild' of null
    at detach (index.mjs:142)
    at Object.d (Span.svelte:2)
    at destroy_component (index.mjs:1220)
    at Object.d (ClassAdder.svelte:2)
    at destroy_component (index.mjs:1220)
    at Object.d (SensorList.svelte:61)
    at Object.d (Item.svelte:43)
    at Object.d (Item.svelte:18)
    at destroy_component (index.mjs:1220)
    at Object.d (SensorList.svelte:61)

Applying the previous fix from @sinistra allows me to continue (Thanks for that sinistra much appreciated)

For reference my dependencies are as follows:-

  "devDependencies": {
    "@fortawesome/fontawesome-pro": "^5.10.1",
    "cross-env": "^5.2.1",
    "css-loader": "^2.1.1",
    "mini-css-extract-plugin": "^0.6.0",
    "node-sass": "^4.12.0",
    "sass-loader": "^7.3.1",
    "serve": "^11.1.0",
    "style-loader": "^0.23.1",
    "svelte": "^3.9.1",
    "svelte-loader": "^2.13.3",
    "svelte-material-ui": "^1.0.0-beta.9",
    "svelte-spa-router": "^1.2.0",
    "webpack": "^4.39.3",
    "webpack-cli": "^3.3.7",
    "webpack-dev-server": "^3.8.0"
  },
  "dependencies": {
    "@simonwep/pickr": "^1.2.6",
    "@stomp/stompjs": "^5.4.2",
    "canvas-gauges": "^2.1.5",
    "chart.js": "^2.8.0",
    "date-fns": "^2.1.0",
    "highcharts": "^7.1.2",
    "masonry-layout": "^4.2.2",
    "packery": "^2.1.2",
    "pnotify": "^4.0.0",
    "sockjs": "^0.3.19"
  }

Not complaining, Svelte is AWESOME!!

Why is this closed? I still have to manually add this to make my app work:

function detach(node) {
	if(node.parentNode) {
		node.parentNode.removeChild(node);
	}
}

@InstanceOfMichael I can't comment on your specific use case but my issue is no longer reproducible against version 3.13.0-alpha.17 after confirming the patch is no longer in place e.g.

function detach(node) {
    node.parentNode.removeChild(node);
}

I am actually not sure if anything changed within Svelte or just reworking my code resolved the issue (I was previously not using a unique enough key within my {#each...})

I appreciate this probably doesn't help you but thought I would provide an update.

I'm still facing this issue:

"devDependencies": {
    "@rollup/plugin-alias": "^2.2.0",
    "dotenv": "^8.2.0",
    "node-sass": "^4.13.0",
    "rollup": "^1.26.3",
    "rollup-plugin-commonjs": "^10.0.0",
    "rollup-plugin-livereload": "^1.0.0",
    "rollup-plugin-multi-entry": "^2.1.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-postcss": "^2.0.3",
    "rollup-plugin-replace": "^2.2.0",
    "rollup-plugin-svelte": "^5.0.3",
    "rollup-plugin-terser": "^5.1.2",
    "sirv-cli": "^0.4.4",
    "svelte": "^3.14.1",
    "svelte-preprocess": "^3.2.6"
  },
index.mjs:147 Uncaught (in promise) TypeError: Cannot read property 'removeChild' of null
    at detach (index.mjs:147)
    at detach_dev (index.mjs:1430)
    at update (index.mjs:637)
    at flush (index.mjs:611)

One very specific block of code that's causing this issue is this very simple if statement in my code:

{#if $someStore}
    <i class="fas fa-angle-right" aria-hidden="true"></i>
{:else}
    <i class="fas fa-angle-down" aria-hidden="true"></i>
{/if}

Removing this piece of code fixes the issue for me, But I cannot figure out why this is happening, the error triggers whenever there's an update to the store or any other reactive value.

I seem to have a very similar issue to @jasdeepsingh (I'm on svelte 3.0.0):

{#if $objectType === "blob"}
  <FileSource />
{:else}
  <FileList />
{/if}
Uncaught (in promise) TypeError: Cannot read property 'removeChild' of null
    at detach (index.mjs:146)
    at detach_dev (index.mjs:1372)
    at Object.destroy [as d] (FileList.svelte:116)
    at Object.destroy [as d] (FileList.svelte:92)

Weirdly this issue doesn't happen if I add some debug statements to the file with the if branch like so:

revision: {$revision}<br />
objectPath: {$objectPath}<br />
objectType: {$objectType}<br />

{#if $objectType === "blob"}
...

The upgrade to Svelte 3.15.0 fixed it for me.

function detach(node) {
	if(node.parentNode) {
		node.parentNode.removeChild(node);
	}
}

This answer is the only fix, that worked for me. I'm using Svelte 3.20.1

I'm using a third party library (sortable.js) where items are cloned into a dropzone. From there, they can be deleted again by a button (which removes the DOM node). Each item is a Item.svelte component. Dropzone.svelte is the wrapper.

As soon as i delete an item out of the dropzone and try to change the route, the parentNode.removeChild error appears in the console.

I also tried to add an additional wrapper within Item.svelte and just delete its content, rather than the node itself. This would work as well, but it causes side effects with the third party library and would require additional logic.

So, what is the point of not checking if there is a parentNode in any case in the internal/index.mjs file? Feels kinda unsafe to change a file in the node modules.

I am also having the above issue still, and I am trying to just use a dynamic component <svelte:component>

Is there a fix for this? I believe I am using svelte 3.23.2 (based on the Changelog.md file).

The following works:

function filterAndRenderMath(topics) {
     filter(selectedTags);
     await tick();
     // renderMathInElement is defined by the KaTeX autorender, sourced in html file.
     //   if (typeof(renderMathInElement) !== "undefined") {
     //       renderMathInElement(document.body);
       // }
}

But if I uncomment the commented lines: it gives me the error mentioned above, if the selectedTags variable changes. Essentially, svelte is not playing well with KaTeX. Any workarounds I can use?

If possible, I would prefer not to change the lines in internal.mjs, as suggested above. @burningTyger mentioned something about destroying the component and rerendering. Can someone please point out how I can do that?

Would really appreciate your help. I am a svelte newbie.

Just wanted to update with the things I tried:

I searched some more for how I could destroy the content that was giving trouble and re-render.
It appears that putting that part in a #if block and setting it to first to false and and then true could work. I tried that, but that did not help me.

Then, I tried the solution suggested by @ciri. The file he mentions does not exist in svelte 3.23.2. But I found that content in both svelte/internal/index.js and svelte/internal/index.mjs. By itself, the solution did not work.

Both of the above combined, however, do work.

I've also seen it happen when some library replaced DOM objects leaving it in a state that svelte is confused about.

easily reproducible by embedding twitter or instagram embed widgets in sapper;

Still running in this issue. I use a lot of dynamic components svelte:component that are leading into huge changes in the DOM (typically enterprise web application with many different tabs). I think it is related to the usage of svelte transitions. Made all of them to local transitions, but still running into this issue.

function detach(node) { if(node.parentNode) { node.parentNode.removeChild(node); } }

The code above fixes the error, but then my DOM is not correct and some elements are still there. Sometimes this is a crazy UI behaviour when something from an other Tab is merged into the new one. Is there any other solution?

It fixed the error on my project too with:
function detach(node) { if(node.parentNode) { node.parentNode.removeChild(node); } }

I can not understand why it should effect the DOM negativ like @torgebauer wrote.

I am still having this issue.

commented

@orgertot & @torgebauer , where did you put this line?
function detach(node) { if(node.parentNode) { node.parentNode.removeChild(node); } }

I don't find the root cause of my Cannot read property 'removeChild' of null, so I would like to check if it's null like you.
Any hint on how to find the root cause?

Please stop commenting on a closed issue.

It's not helpful commenting on a closed issue, and even though you may get the same error, it may due to different reasons.

So, please, if you need support on this, please comment your repro on this new issue i just created.

@jycouet @sudomaxime @torgebauer @orgertot @shedali @clineamb @kilianso