koala73/worldmonitor · error · Error
cannot read dashboard entry ${entryPath}: ${error.message}
Error message
cannot read dashboard entry ${entryPath}: ${error.message} What it means
After resolving the entry chunk name from dashboard.html, deferredDashboardAppDependencies reads dist/assets/<entry>.js to parse the Vite loader. If the file cannot be read, it throws including the underlying fs error message. This catches HTML/asset mismatches where the referenced entry chunk is missing from the build output.
Solutions
- Run a fresh full BUILD_COMMANDS.dashboard build so HTML and assets/ are regenerated together
- Confirm dist/assets/<entryName>.js exists (compare with the src in dashboard.html)
- Wipe dist/ and rebuild if stale hashed chunks linger from an earlier build
- Fix the distDir argument if it points at a directory missing the assets/ output
Example fix
// before: stale mismatched output rm dist/assets/*.js // HTML still references removed entry // after rm -rf dist && npm run build:dashboard
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from 'node:fs';
const entry = dist/assets/<entryName from html>;
if (!existsSync(entry)) throw new Error(`entry chunk missing: ${entry} — rebuild dist/`); Type guard
const entryChunkExists = (distDir, entryName) => existsSync(join(distDir, 'assets', entryName));
Try / catch
try {
const deps = deferredDashboardAppDependencies(distDir);
} catch (e) {
if (e.message.includes('cannot read dashboard entry')) {
console.error('HTML/asset mismatch — wipe dist/ and rebuild the dashboard');
process.exitCode = 1;
} else throw e;
} Prevention
- Regenerate HTML and assets together; never delete hashed chunks selectively
- Wipe dist/ fully before a fresh build to avoid stale hash mismatches
- Don't share dist/ between concurrent builds
- Verify CI caches include assets/, not just HTML
When it happens
Trigger: dashboard.html references an entry asset that does not exist in dist/assets/ — partial/cleaned build output, stale HTML from a previous build paired with pruned assets, wrong distDir whose assets/ subfolder lacks the file, or a permissions problem on the chunk.
Common situations: CI caches dashboard.html but not assets/; developer deletes assets/*.js while keeping HTML; concurrent builds racing and replacing hashed chunks; symlinked dist where assets/ resolves incorrectly.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- cannot read ${dashboardPath} — run: ${BUILD_COMMANDS.dashboa
- ${stale.map((output) => output.relativePath).join(' and ')}
- no initial JS assets referenced by ${dashboardPath} — run: $
- no module entry script in ${dashboardPath} — run: ${BUILD_CO
- is missing methodology prose
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/bedb70d3fec3cb4a.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/bundle-budgets.mjs:208
* where the indices point into one `m.f=[…]` table and the list starts with
* the imported chunk itself. Anything that breaks that shape throws: a parser
* that silently measured the wrong list would let the application graph grow
* unseen.
*/
export function deferredDashboardAppDependencies(distDir) {
const { dashboardPath, html } = readDashboardHtml(distDir);
const entryUrl = /<script\b[^>]*\btype=["']module["'][^>]*\bsrc=["']([^"']+\.js(?:[?#][^"']*)?)["']/i
.exec(html)?.[1];
const entryName = entryUrl ? assetFileNameFromUrl(entryUrl) : null;
if (!entryName) {
throw new Error(`no module entry script in ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}`);
}
const entryPath = join(distDir, 'assets', entryName);
let source;
try {
source = readFileSync(entryPath, 'utf8');
} catch (error) {
throw new Error(`cannot read dashboard entry ${entryPath}: ${error.message}`);
}
const appImport = /import\(\s*["']\.\/(App-[A-Za-z0-9_-]{8}\.js)["']\s*\)/.exec(source);
if (!appImport) return null;
const appFile = appImport[1];
const unsupported = (reason) => new Error(
`${entryPath}: ${reason} for the deferred ./${appFile} import — the Vite loader shape changed; `
+ 'update deferredDashboardAppDependencies in scripts/bundle-budgets.mjs',
);
const afterImport = source.slice(appImport.index + appImport[0].length);
const depsCall = /__vite__mapDeps\(\[([\d,\s]*)\]\)/.exec(afterImport);
if (!depsCall || afterImport.slice(0, depsCall.index).includes('import(')) {
throw unsupported('no Vite preload list');
}
const tableSource = /m\.f=\[([^\]]*)\]/.exec(source)?.[1];
let table;
try {View on GitHub (pinned to 7d06c8633d)