How to debug Nuxt Hierarchy Request Error
Hydration is tricky (physically and programatically), debugging production-only issues is even trickier (mentally and emotionally).
So what happens when you have to debug a production-only instance of a Nuxt Hydration error? Recently at VoucherCodes we were tasked with this problem, and we wanted to share our journey to a successful outcome.
What are we dealing with?
Nuxt allows for Server-side Rendering (SSR), whereby your Server generates the HTML for a page. Once the client (i.e. your browser) receives the webpage, the HTML on the server and client need to be exactly the same before a user can interact with the page — otherwise you can end up with a HierarchyRequestError.
Console logs for a HierarchyRequestError can present themselves as:
HierarchyRequestError: Failed to execute 'appendChild' on 'Node': This node type does not support this method
HierarchyRequestError: The operation would yield an incorrect node tree.
The above is telling us that there’s a mismatch between the server and client HTML — it’s just not telling us where or what that exact HTML is 🤨
What do we know so far?
Checking our Error Reporting logs, we found nothing of great clarity. All we were being given was a stacktrace of the HierarchyRequestError:
HierarchyRequestError Failed to execute 'appendChild' on 'Node': This node type does not support this method.
node_modules/vue/dist/vue.runtime.esm.js:5761:7 Object.appendChild
node_modules/vue/dist/vue.runtime.esm.js:6086:16 insert
node_modules/vue/dist/vue.runtime.esm.js:6002:8 createElm
node_modules/vue/dist/vue.runtime.esm.js:6097:8 createChildren
node_modules/vue/dist/vue.runtime.esm.js:6433:10 hydrate
node_modules/vue/dist/vue.runtime.esm.js:6537:16 f.__patch__
node_modules/vue/dist/vue.runtime.esm.js:3960:18 f.t._update
node_modules/vue/dist/vue.runtime.esm.js:4081:9 f.r
node_modules/vue/dist/vue.runtime.esm.js:4495:24 kn.get
Hmm. We have no idea where to start looking — all we’re being told is that the error is being thrown from the Vue runtime with no traces of our own code 🤔
Let’s see if we can intercept this code and dump out some useful data…
Leveraging Webpack aliases
We can see from the above logs that we’re dealing with an error thrown from a function called appendChild
, which exists in the Vue runtime.
We need to hook into this in order to dump out some information, which is where Webpack aliases can be of use.
These are essentially references to where code in your project should be located. So this should mean we can tell it where the Vue runtime should be located…
Let’s make a copy of the node_modules/vue/dist/vue.runtime.esm.js
file that is throwing the error and paste it to a known path in our codebase which we can control. We can then set up a Webpack alias to use this file rather than the one in node_modules
by declaring the following in our nuxt.config file:
export default {
…
build: {
extend(config, { isDev }) {
if (isDev) {
config.resolve.alias.vue$ = ‘./newfolder/vue.runtime.esm.js’;
} else {
config.resolve.alias.vue$ = ‘./newfolder/vue.runtime.minified.esm.js’; // Remember to serve a minified version in Production!
}
}
}
}
We now have our own Vue runtime (with great power…)! 😏
Adding supplementary information
With our newfound power, we can start adding the information we need to our own Vue runtime file. A simple try/catch to the appendChild(node, child)
function should suffice:
function appendChild(node, child) {
try {
node.appendChild(child);
} catch (error) {
// Dump out information about the node & child params here!
throw error;
}
}
This is a massive win — we have direct access to the function throwing the error and can dump out information about the HTML elements responsible! We also do not compromise the performance of the Vue runtime by using a try/catch.
Logging the className, tagName and dataset of the node
and child
should give us enough of an identifier of the exact HTML elements 🤞
You can hook into the public Nuxt instance using
window.$nuxt
— allowing you to hook into your error reporting software to fire an alert/leave breadcrumbs. Remember to minify changes to this copied Vue runtime file and ensure you’re serving that in Production!
Jackpot!
Our error reporting software was now able to tell us the HTML elements that were causing the HierarchyRequestError. While it didn’t exactly tell us how to fix the error, we knew which Vue component was responsible.
Such hydration errors in Nuxt are often caused when convention is not followed exactly enough — so it’s important to do a sanity check from start to finish of the SSR process in the offending Vue component(s). Once we addressed potential causes that could trip up SSR, we noticed a sharp reduction in HierarchyRequestErrors 🎉
Have you heard? We’re hiring at VoucherCodes! Check out our careers page here.