VLT seemed breaking Volto for me when I reinstall/rebuild it locally.
Cause/Solution: A conflicting pnpm installed VLT instance/version kept a duplicate react in the App.
- using a plain
pnpm list
command discovered a hidden dependency.- using
pnpm remove [listed vlt]
and a remainingyarn
cleared the conflict- VLT now works again!
- Details see comment below:
Background / Symptoms
- As soon as I install VLT in a fresh Cookieplone project, the page no longer loads in localhost:3000.
- The logo flashes briefly and the page remains white.
- React can no longer access resources with ‘unauthorized’.
Browser console:GET http://localhost:3000/ 401 (Unauthorized)
- Classic backend is running and usable.
Short version
A fresh Cookieplone project installs and vanilla Volto works
- VLT is added with its companion Add-ons in
package.json
and the corresponding theme setting involto.config.js
- Also checked the variant where addons are listed in
volto.config.js
As soon as I remove only VLT it works again (all standard addons work in vanilla Volto)
Crosscheck:
- Same thing with GitHub - plone/tagung.plone.de (HEAD -> main, tag: 0.8.0) and rebuild with make install: (VLT 6.0.0a15)
Long version
Yesterday I made a new fresh Cookiecutter run for the WPD and wanted to document it in German for the Cologne Python Usergroup PyCologne.
The evening before I had shown the latest version of Cookieplone live with the documentation template and got it running locally. I did not show VLT Install again.
Adding VLT breaks my installs now.
Prerequisites
These prerequisites are installed and this worked before
List of currently locally installed versions of Plone CI fullstack tools
-----------------------
python3 version: Python 3.13.2
uvx version: uv-tool-uvx 0.6.7 (029b9e1fc 2025-03-17)
nvm version: 0.39.5
npm version: 10.9.2
pnpm version: 10.4.0
node version: v22.14.0
docker version: Docker version 28.0.4, build b8034c0
Cookieplone version Cookieplone 0.9.6 from /Users/astro/Library/Caches/uv/archive-v0/_l9yZJ_DFVFwpfkcrPYa4/lib/python3.13/site-packages/cookieplone (Cookiecutter 2.6.0, Python 3.13.2 (main, Feb 4 2025, 14:51:09) [Clang 16.0.0 (clang-1600.0.26.6)]) Made with ❤️ by the Plone Community
make version: GNU Make 3.81 Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This program built for i386-apple-darwin11.3.0
gmake version: GNU Make 4.4.1 Built for aarch64-apple-darwin22.3.0 Copyright (C) 1988-2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
-----------------------
Mi 9 Apr 2025 16:37:20 CEST Done!
Procedure
- in
package.json
add VLT version in dependencies - in
volto.config.js
add the addons and the theme setting - check / linting
- run
make install
- start two terminals with:
make backend-start
andmake frontend-start
- open http://localhost:3000/
After adding VLT in the working naked Volto, the default site renders unusable.
Error Details
-
Logo flashes briefly (probably the preload stuff)
-
the page stays white.
-
in the Page Source: Only the React framework is visible in the DOM Inspector.
- The body React Error: very often ‘Unauthorised’ The Classic page runs normally.
-
terminal output:
... 🎭 Volto started at 0.0.0.0:3000 🚀 (node:74391) [DEP0060] DeprecationWarning: The `util._extend` API is deprecated. Please use Object.assign() instead. (Use `node --trace-deprecation ...` to show where the warning was created)
node --trace-deprecation ... node:internal/modules/cjs/loader:1228 throw err; ^ Error: Cannot find module '/Users/astro/github/acsr.de/ultra-experience.acsr.de/acsr-plone/...' at Function._resolveFilename (node:internal/modules/cjs/loader:1225:15) at Function._load (node:internal/modules/cjs/loader:1055:27) at TracingChannel.traceSync (node:diagnostics_channel:322:14) at wrapModuleLoad (node:internal/modules/cjs/loader:220:24) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5) at node:internal/main/run_main_module:36:49 { code: 'MODULE_NOT_FOUND', requireStack: [] } Node.js v22.14.0
Which mistake I am missing?
As soon as you remove VLT in addons and dependencies of package.json
, and the theme setting in volto.config.js
, everything works again. All other block add-ons run in vanilla Volto 18.11.1.
- tested wit VLT 6.0.0a15, a16 or a21
- manual installed these VLT alpha versions additionally using pnpm
- entries in package.json
- volto.config.js
- add-ons deactivated individually
- wiped everything with
make clean
andmake install
again. - multilingual on/off (should actually be activated for my purposes).
- cleared the cache in Chrome!
- same in Firefox and Safari, and in private sessions
Unchanged code from tagung.plone.de, same effect!
- pulled plone/tagung.plone.de main (version from 10th April with image scaling).
- run
make install
again - page starts with the same error:
- http://localhost:3000/ remains empty.
- logo flashes briefly
- page remains white
- "Unauthorized" in the react page source
Console Errors in Browser:
GET http://localhost:3000/ 401 (Unauthorized)
Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
react.development.js:1618 Uncaught TypeError: Cannot read properties of null (reading 'useContext')
at useContext (react.development.js:1618:1)
at useReduxContext (useReduxContext.js:13:1)
at useSelector (useSelector.js:50:1)
at Header (Header.jsx:153:1)
at renderWithHooks (react-dom.development.js:16305:1)
at mountIndeterminateComponent (react-dom.development.js:20074:1)
at beginWork (react-dom.development.js:21587:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
at invokeGuardedCallback (react-dom.development.js:4277:1)
at beginWork$1 (react-dom.development.js:27451:1)
at performUnitOfWork (react-dom.development.js:26557:1)
at workLoopSync (react-dom.development.js:26466:1)
at renderRootSync (react-dom.development.js:26434:1)
at performConcurrentWorkOnRoot (react-dom.development.js:25738:1)
at workLoop (scheduler.development.js:266:1)
at flushWork (scheduler.development.js:239:1)
at MessagePort.performWorkUntilDeadline (scheduler.development.js:533:1)
Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.
other errors in log:
grep "Uncaught" console.log
react.development.js:1618 Uncaught TypeError: Cannot read properties of null (reading 'useContext')
react.development.js:1618 Uncaught TypeError: Cannot read properties of null (reading 'useContext')
invariant.js:4 Uncaught Error: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.
react-dom.development.js:19849 Uncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
react.development.js:1618 Uncaught TypeError: Cannot read properties of null (reading 'useContext')
invariant.js:4 Uncaught Error: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.
react.development.js:1618 Uncaught TypeError: Cannot read properties of null (reading 'useContext')
invariant.js:4 Uncaught Error: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.
react.development.js:1618 Uncaught TypeError: Cannot read properties of null (reading 'useContext')
this is my HTML body:
<body class="view-viewview siteroot is-authenticated public-ui">
<div role="navigation" aria-label="Toolbar" id="toolbar"></div>
<div id="main"></div>
<div role="complementary" aria-label="Sidebar" id="sidebar"></div>
<script charset="UTF-8">
window.__data = { "router": { "location": { "pathname": "\u002F", "search": "", "hash": "", "state": undefined, "key": "y4jkfo", "query": {} },
"action": "POP" },
"intl": { "defaultLocale": "en", "locale": "en", "messages": undefined },
"reduxAsyncConnect": { "loaded": true, "loadState": { "content": { "loading": false, "loaded": false, "error": { "status": 401, "response": { "req": { "method": "GET", "url": "http:\u002F\u002Flocalhost:3000\u002F++api++\u002F?expand=breadcrumbs,actions,types,navroot,navigation&expand.navigation.depth=3", "data": undefined, "headers": { "user-agent": "node-superagent\u002F3.8.2", "x-forwarded-for": "127.0.0.1", "x-forwarded-host": "localhost", "authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTc0NDM3Nzk5OSwiZnVsbG5hbWUiOiIifQ.KvkCdW0rmdRG5F6-rFNEA-rGZ6HDfH_NwFSNfBITeXg", "accept": "application\u002Fjson" } },
"header": { "cache-control": "max-age=10, s-maxage=60, proxy-revalidate, public", "connection": "close", "content-length": "59", "content-type": "application\u002Fjson", "date": "Fri, 11 Apr 2025 07:32:38 GMT", "etag": "\"||475|de|Plone Default|0|0\"", "expires": "Fri, 11 Apr 2025 07:32:48 GMT", "server": "waitress", "vary": "Accept", "via": "waitress", "x-cache-operation": "plone.app.caching.terseCaching", "x-cache-rule": "plone.content.dynamic", "x-frame-options": "SAMEORIGIN", "x-powered-by": "Zope (www.zope.dev), Python (www.python.org)" },
"status": 401, "text": "{\n \"message\": \"Unauthorized()\",\n \"type\": \"Unauthorized\"\n}" } } },
"workflow": { "loading": false, "loaded": true, "error": null },
"GET_SITE": { "loading": false, "loaded": true, "error": null } },
"workflow": { "@id": "http:\u002F\u002Flocalhost:3000\u002F@workflow", "history": [], "transitions": [] },
"GET_SITE": { "@id": "http:\u002F\u002Flocalhost:3000\u002F@site", "features": { "filter_aliases_by_date": true, "multilingual": false },
"plone.allowed_sizes": ["icon 32:32", "tile 64:64", "thumb 128:128", "mini 200:65536", "preview 400:65536", "teaser 600:65536", "large 800:65536", "larger 1000:65536", "great 1200:65536", "huge 1600:65536"], "plone.available_languages": ["de"], "plone.default_language": "de", "plone.portal_timezone": "UTC", "plone.robots_txt": "Sitemap: {portal_url}\u002Fsitemap-index.xml\n\n# Define access-restrictions for robots\u002Fspiders\n# http:\u002F\u002Fwww.robotstxt.org\u002Fwc\u002Fnorobots.html\n\nUser-agent: *\nDisallow: \u002Fsearch\nDisallow: \u002Flogin\n\n# Add Googlebot-specific syntax extension to exclude forms\n# that are repeated for each piece of content in the site\n# the wildcard is only supported by Googlebot\n# http:\u002F\u002Fwww.google.com\u002Fsupport\u002Fwebmasters\u002Fbin\u002Fanswer.py?answer=40367&ctx=sibling\n\nUser-Agent: Googlebot\nDisallow: \u002F*login\nDisallow: \u002F*search\nDisallow: \u002F*edit\n", "plone.site_logo": "http:\u002F\u002Flocalhost:3000\u002F@@site-logo\u002FPlone Tagung 2025 Signet-outline.svg", "plone.site_title": "tagung.plone.de" } },
"actions": { "error": null, "actions": { "object": [], "object_buttons": [], "site_actions": [], "user": [], "document_actions": [], "portal_tabs": [] },
"loaded": false, "loading": false },
"addons": { "error": null, "installedAddons": [], "availableAddons": [], "upgradableAddons": [], "loaded": false, "loading": false },
"apierror": { "error": { "status": 401, "response": { "req": { "method": "GET", "url": "http:\u002F\u002Flocalhost:3000\u002F++api++\u002F?expand=breadcrumbs,actions,types,navroot,navigation&expand.navigation.depth=3", "data": undefined, "headers": { "user-agent": "node-superagent\u002F3.8.2", "x-forwarded-for": "127.0.0.1", "x-forwarded-host": "localhost", "authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTc0NDM3Nzk5OSwiZnVsbG5hbWUiOiIifQ.KvkCdW0rmdRG5F6-rFNEA-rGZ6HDfH_NwFSNfBITeXg", "accept": "application\u002Fjson" } },
"header": { "cache-control": "max-age=10, s-maxage=60, proxy-revalidate, public", "connection": "close", "content-length": "59", "content-type": "application\u002Fjson", "date": "Fri, 11 Apr 2025 07:32:38 GMT", "etag": "\"||475|de|Plone Default|0|0\"", "expires": "Fri, 11 Apr 2025 07:32:48 GMT", "server": "waitress", "vary": "Accept", "via": "waitress", "x-cache-operation": "plone.app.caching.terseCaching", "x-cache-rule": "plone.content.dynamic", "x-frame-options": "SAMEORIGIN", "x-powered-by": "Zope (www.zope.dev), Python (www.python.org)" },
"status": 401, "text": "{\n \"message\": \"Unauthorized()\",\n \"type\": \"Unauthorized\"\n}" } },
"statusCode": { "req": { "method": "GET", "url": "http:\u002F\u002Flocalhost:3000\u002F++api++\u002F?expand=breadcrumbs,actions,types,navroot,navigation&expand.navigation.depth=3", "data": undefined, "headers": { "user-agent": "node-superagent\u002F3.8.2", "x-forwarded-for": "127.0.0.1", "x-forwarded-host": "localhost", "authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTc0NDM3Nzk5OSwiZnVsbG5hbWUiOiIifQ.KvkCdW0rmdRG5F6-rFNEA-rGZ6HDfH_NwFSNfBITeXg", "accept": "application\u002Fjson" } },
"header": { "cache-control": "max-age=10, s-maxage=60, proxy-revalidate, public", "connection": "close", "content-length": "59", "content-type": "application\u002Fjson", "date": "Fri, 11 Apr 2025 07:32:38 GMT", "etag": "\"||475|de|Plone Default|0|0\"", "expires": "Fri, 11 Apr 2025 07:32:48 GMT", "server": "waitress", "vary": "Accept", "via": "waitress", "x-cache-operation": "plone.app.caching.terseCaching", "x-cache-rule": "plone.content.dynamic", "x-frame-options": "SAMEORIGIN", "x-powered-by": "Zope (www.zope.dev), Python (www.python.org)" },
"status": 401, "text": "{\n \"message\": \"Unauthorized()\",\n \"type\": \"Unauthorized\"\n}" },
"connectionRefused": false, "message": "Unauthorized()" },
"aliases": { "add": { "loaded": false, "loading": false, "error": null },
"remove": { "loaded": false, "loading": false, "error": null },
"get": { "loaded": false, "loading": false, "error": null },
"items": [] },
"breadcrumbs": { "error": null, "items": [], "root": null, "loaded": false, "loading": false },
"browserdetect": { "name": "chrome", "version": "134.0.0", "os": "Mac OS", "type": "browser" },
"comments": { "add": { "loaded": false, "loading": false, "error": null },
"delete": { "loaded": false, "loading": false, "error": null },
"update": { "loaded": false, "loading": false, "error": null },
"list": { "loaded": false, "loading": false, "error": null },
"items": [], "items_total": null, "permissions": {},
"next": null },
"content": { "create": { "loaded": false, "loading": false, "error": null },
"delete": { "loaded": false, "loading": false, "error": null },
"get": { "loading": false, "loaded": false, "error": { "status": 401, "response": { "req": { "method": "GET", "url": "http:\u002F\u002Flocalhost:3000\u002F++api++\u002F?expand=breadcrumbs,actions,types,navroot,navigation&expand.navigation.depth=3", "data": undefined, "headers": { "user-agent": "node-superagent\u002F3.8.2", "x-forwarded-for": "127.0.0.1", "x-forwarded-host": "localhost", "authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTc0NDM3Nzk5OSwiZnVsbG5hbWUiOiIifQ.KvkCdW0rmdRG5F6-rFNEA-rGZ6HDfH_NwFSNfBITeXg", "accept": "application\u002Fjson" } },
"header": { "cache-control": "max-age=10, s-maxage=60, proxy-revalidate, public", "connection": "close", "content-length": "59", "content-type": "application\u002Fjson", "date": "Fri, 11 Apr 2025 07:32:38 GMT", "etag": "\"||475|de|Plone Default|0|0\"", "expires": "Fri, 11 Apr 2025 07:32:48 GMT", "server": "waitress", "vary": "Accept", "via": "waitress", "x-cache-operation": "plone.app.caching.terseCaching", "x-cache-rule": "plone.content.dynamic", "x-frame-options": "SAMEORIGIN", "x-powered-by": "Zope (www.zope.dev), Python (www.python.org)" },
"status": 401, "text": "{\n \"message\": \"Unauthorized()\",\n \"type\": \"Unauthorized\"\n}" } } },
"order": { "loaded": false, "loading": false, "error": null },
"update": { "loaded": false, "loading": false, "error": null },
"updatecolumns": { "loaded": false, "loading": false, "error": null },
"lock": { "loaded": false, "loading": false, "error": null },
"unlock": { "loaded": false, "loading": false, "error": null },
"data": null, "subrequests": {},
"uploadedFiles": 0 },
"controlpanels": { "get": { "loaded": false, "loading": false, "error": null },
"list": { "loaded": false, "loading": false, "error": null },
"update": { "loaded": false, "loading": false, "error": null },
"post": { "loaded": false, "loading": false, "error": null },
"delete": { "loaded": false, "loading": false, "error": null },
"controlpanel": null, "controlpanels": [], "systeminformation": null, "databaseinformation": null },
"clipboard": { "action": null, "source": null, "request": { "loaded": false, "loading": false, "error": null } },
"diff": { "error": null, "data": [], "loaded": false, "loading": false },
"emailNotification": { "error": null, "loaded": false, "loading": false },
"emailSend": { "error": null, "loaded": false, "loading": false },
"form": { "global": {},
"ui": { "selected": null, "multiSelected": [], "gridSelected": null, "hovered": null } },
"groups": { "create": { "loaded": false, "loading": false, "error": null },
"delete": { "loaded": false, "loading": false, "error": null },
"get": { "loaded": false, "loading": false, "error": null },
"list": { "loaded": false, "loading": false, "error": null },
"update": { "loaded": false, "loading": false, "error": null },
"groups": [], "group": {} },
"history": { "entries": [], "get": { "error": null, "loaded": false, "loading": false },
"revert": { "error": null, "loaded": false, "loading": false } },
"linkIntegrity": { "error": null, "loaded": false, "loading": false, "result": null },
"messages": { "messages": [] },
"navigation": { "error": null, "items": [], "loaded": false, "loading": false },
"querystring": { "error": null, "indexes": {},
"sortable_indexes": {},
"loaded": false, "loading": false },
"querystringsearch": { "error": null, "items": [], "total": 0, "loaded": false, "loading": false, "batching": {},
"subrequests": {} },
"relations": { "relations": { "error": null, "loaded": false, "loading": false, "data": null },
"stats": { "error": null, "loaded": false, "loading": false, "data": null },
"create": { "error": null, "loaded": false, "loading": false },
"delete": { "error": null, "loaded": false, "loading": false },
"rebuild": { "error": null, "loaded": false, "loading": false },
"subrequests": {} },
"roles": { "error": null, "roles": [], "loaded": false, "loading": false },
"rules": { "add": { "loaded": false, "loading": false, "error": null },
"enable": { "loaded": false, "loading": false, "error": null },
"disable": { "loaded": false, "loading": false, "error": null },
"apply": { "loaded": false, "loading": false, "error": null },
"unapply": { "loaded": false, "loading": false, "error": null },
"rem…
</script>
<script id="__LOADABLE_REQUIRED_CHUNKS__" type="application/json" crossorigin="true">
[]
</script>
<script id="__LOADABLE_REQUIRED_CHUNKS___ext" type="application/json" crossorigin="true">
{ "namedChunks": [] }
</script>
<script async="" data-chunk="client" src="http://localhost:3001/static/js/runtime~client.js" crossorigin="true"></script>
<script async="" data-chunk="client" src="http://localhost:3001/static/js/client.js" crossorigin="true"></script>
</body>