<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Webpack on Lessons learned</title><link>https://eghuro.cz/tags/webpack/</link><description>Recent content in Webpack on Lessons learned</description><generator>Hugo</generator><language>en-us</language><copyright>© Alexandr Mansurov · Licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)</copyright><lastBuildDate>Mon, 22 Jun 2026 13:01:00 +0200</lastBuildDate><atom:link href="https://eghuro.cz/tags/webpack/index.xml" rel="self" type="application/rss+xml"/><item><title>Next.js "Cannot read properties of undefined (reading 'length')" in installChunk: two processes share .next</title><link>https://eghuro.cz/posts/nextjs-installchunk-shared-next-dir/</link><pubDate>Mon, 22 Jun 2026 13:01:00 +0200</pubDate><guid>https://eghuro.cz/posts/nextjs-installchunk-shared-next-dir/</guid><description>&lt;p&gt;I opened the dashboard of my Next.js app and got a 500 error:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; GET /app/dashboard 500 in 285ms&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ⨯ TypeError: Cannot read properties of undefined (reading &amp;#39;length&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; at &amp;lt;unknown&amp;gt; (.next/server/app/app/accounts/page.js:685:47)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; at Object.&amp;lt;anonymous&amp;gt; (.next/server/app/app/accounts/page.js:688:3) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; page: &amp;#39;/app/accounts&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; GET /app/accounts 500 in 278ms&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the stack points into generated &lt;code&gt;.next/server/.../page.js&lt;/code&gt; and the full trace ends in &lt;code&gt;installChunk&lt;/code&gt; in &lt;code&gt;webpack-runtime.js&lt;/code&gt;, your code is fine. Another Next process has written into the &lt;code&gt;.next&lt;/code&gt; directory your dev server is reading from.&lt;/p&gt;&#10;&#10;&lt;h2 id="the-setup"&gt;The setup &lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Next.js 15.5 with webpack in dev, in a pnpm monorepo (the app lives in &lt;code&gt;apps/web&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;pnpm dev&lt;/code&gt; running in my terminal on port 3000&lt;/li&gt;&#10;&lt;li&gt;A coding agent working in the same checkout, which checks its work with &lt;code&gt;pnpm build&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;h2 id="what-went-wrong"&gt;What went wrong &lt;/h2&gt;&#10;&lt;p&gt;I asked the agent to fix the 500. It did what anyone would do with &lt;code&gt;reading 'length'&lt;/code&gt;: it grepped the app for &lt;code&gt;.length&lt;/code&gt;. The accounts page didn&amp;rsquo;t touch a collection at all, so the agent followed the authenticated layout into the auth code and suspected an import there. Then it opened the generated &lt;code&gt;page.js&lt;/code&gt; at line 685 and found webpack glue, not application code.&lt;/p&gt;&#10;&lt;p&gt;To reproduce, the agent ran &lt;code&gt;pnpm build&lt;/code&gt;, which succeeded, and then started its own &lt;code&gt;next dev -p 3001&lt;/code&gt; next to mine. The first request to &lt;code&gt;/app/accounts&lt;/code&gt; returned 200. After a request to the dashboard, both routes returned 500, and this time the error page carried the whole stack:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;TypeError: Cannot read properties of undefined (reading &amp;#39;length&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; at installChunk (apps/web/.next/server/webpack-runtime.js:249:41)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; at __webpack_require__.f.require (apps/web/.next/server/webpack-runtime.js:259:15)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; at apps/web/.next/server/app/app/dashboard/page.js:718:47&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Line 249 is in webpack&amp;rsquo;s chunk loader:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;installChunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;moreModules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunkIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;chunkIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;installedChunks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;chunkIds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;chunk&lt;/code&gt; is whatever &lt;code&gt;require(&amp;quot;./&amp;quot; + chunkFile)&lt;/code&gt; returned. &lt;code&gt;chunk.ids&lt;/code&gt; was undefined, so the file on disk was not the chunk this runtime expected. A &lt;code&gt;ps&lt;/code&gt; showed why: two &lt;code&gt;next-server&lt;/code&gt; processes, mine on 3000 and the agent&amp;rsquo;s on 3001, both compiling into &lt;code&gt;apps/web/.next&lt;/code&gt;. On top of that, the agent&amp;rsquo;s &lt;code&gt;next build&lt;/code&gt; had written its production output into the same directory a few minutes earlier.&lt;/p&gt;&#10;&lt;p&gt;Both of the usual ways to reproduce a bug, a fresh build and a second server, are ways to cause this one. Before you reproduce, look for other Next processes on the checkout:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -axo pid,ppid,command &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;[n]ext-server&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;h2 id="fix"&gt;Fix &lt;/h2&gt;&#10;&lt;p&gt;Give &lt;code&gt;next dev&lt;/code&gt; its own output directory in &lt;code&gt;next.config.mjs&lt;/code&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// `next dev` and `next build` generate incompatible webpack chunk graphs.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Keep their output separate so a build cannot break a running dev server.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;distDir&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;development&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.next-dev&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.next&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ignore it in &lt;code&gt;.gitignore&lt;/code&gt;:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-gitignore" data-lang="gitignore"&gt;.next/&#10;.next-dev/&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add its generated types to &lt;code&gt;tsconfig.json&lt;/code&gt;, next to the &lt;code&gt;.next&lt;/code&gt; ones:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;include&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;next-env.d.ts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;**/*.ts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;**/*.tsx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.next/types/**/*.ts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.next-dev/types/**/*.ts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The running dev server picked up the config change and rebuilt into &lt;code&gt;.next-dev&lt;/code&gt;. From then on, &lt;code&gt;next build&lt;/code&gt; writes to &lt;code&gt;.next&lt;/code&gt; and the dev server never reads it.&lt;/p&gt;&#10;&lt;p&gt;To recover without the config change, stop every Next process except one, delete &lt;code&gt;.next&lt;/code&gt; and restart &lt;code&gt;pnpm dev&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;If you&amp;rsquo;re on Next.js 16, you already have this: &lt;code&gt;next dev&lt;/code&gt; writes to &lt;code&gt;.next/dev&lt;/code&gt;, so &lt;a&#10; href="https://nextjs.org/docs/app/api-reference/cli/next"&#10; &#10; target="_blank" rel="noopener"&#10; &#10; &#10;&gt;dev and build can run concurrently&lt;/a&gt;&#10;.&lt;/p&gt;&#10;&#10;&lt;h2 id="the-follow-on-trap-next-envdts"&gt;The follow-on trap: &lt;code&gt;next-env.d.ts&lt;/code&gt; &lt;/h2&gt;&#10;&lt;p&gt;Next rewrites &lt;code&gt;next-env.d.ts&lt;/code&gt; on every dev start and every build, and the file names the types of whichever directory ran last:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;/// &amp;lt;reference path=&amp;#34;./.next-dev/types/routes.d.ts&amp;#34; /&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After every &lt;code&gt;next build&lt;/code&gt;, it says &lt;code&gt;./.next/types/routes.d.ts&lt;/code&gt; instead. The file was tracked, so it showed up as modified in later sessions, and the agents kept &amp;ldquo;fixing&amp;rdquo; it with &lt;code&gt;git show HEAD:apps/web/next-env.d.ts &amp;gt; apps/web/next-env.d.ts&lt;/code&gt;. Do what the &lt;code&gt;.gitignore&lt;/code&gt; from &lt;code&gt;create-next-app&lt;/code&gt; does and ignore the file:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;next-env.d.ts&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; apps/web/.gitignore&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rm --cached apps/web/next-env.d.ts&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;h2 id="why"&gt;Why &lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;next dev&lt;/code&gt; and &lt;code&gt;next build&lt;/code&gt; both default to &lt;code&gt;.next&lt;/code&gt; in Next.js 15, and they write different chunk graphs into it. A second &lt;code&gt;next dev&lt;/code&gt; is no better: two webpack compilers write into one directory, and neither knows about the other. The runtime that is already loaded &lt;code&gt;require()&lt;/code&gt;s a chunk by the name from its own graph, gets a file the other compilation wrote, and fails at &lt;code&gt;chunk.ids.length&lt;/code&gt;. The error says &lt;code&gt;length&lt;/code&gt;, so you go looking for an array in your code.&lt;/p&gt;&#10;&lt;p&gt;Coding agents check their work with &lt;code&gt;next build&lt;/code&gt;, usually while your dev server is still running, so you&amp;rsquo;ll hit this more often than you&amp;rsquo;d think.&lt;/p&gt;&#10;&#10;&lt;h2 id="takeaway"&gt;Takeaway &lt;/h2&gt;&#10;&lt;p&gt;An error from inside &lt;code&gt;installChunk&lt;/code&gt; points at the build directory, so look for a second Next process before you read your own code. Never let two Next processes share a &lt;code&gt;distDir&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;If an agent or a script runs &lt;code&gt;next build&lt;/code&gt; in the checkout where your dev server runs, give dev its own &lt;code&gt;distDir&lt;/code&gt; today.&lt;/p&gt;&#10;</description></item></channel></rss>