koala73/worldmonitor · error · Error
cannot read ${dashboardPath} — run: ${BUILD_COMMANDS.dashboa
Error message
cannot read ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}: ${error.message} What it means
bundle-budgets.mjs measures the built dashboard bundle sizes by parsing dist/dashboard.html. readDashboardHtml wraps readFileSync of that file; if it cannot be read (missing or unreadable), it throws a remediation-aware error telling the developer to run the dashboard build command first. It exists so budget checks fail with an actionable message instead of a bare ENOENT.
Solutions
- Run the dashboard build command (BUILD_COMMANDS.dashboard, e.g. `npm run build:dashboard`) so dist/dashboard.html exists
- Verify the distDir argument passed to the script points at the real Vite output directory
- Check file permissions on dist/dashboard.html if the build output exists but is unreadable
- Re-run a clean full build if dashboard.html exists but is stale/corrupt
Example fix
// before: checking budgets on a clean tree node scripts/bundle-budgets.mjs --dist dist // after: build first, then check npm run build:dashboard && node scripts/bundle-budgets.mjs --dist dist
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from 'node:fs';
if (!existsSync(join(distDir, 'dashboard.html'))) throw new Error(`run the dashboard build before budget checks: ${distDir}/dashboard.html missing`); Type guard
const dashboardBuilt = (distDir) => existsSync(join(distDir, 'dashboard.html'));
Try / catch
try {
measureBudgets(distDir);
} catch (e) {
if (e.message.includes('cannot read') && e.message.includes('dashboard.html')) {
execSync('npm run build:dashboard', { stdio: 'inherit' });
measureBudgets(distDir);
} else throw e;
} Prevention
- Always build the dashboard before running bundle budget checks
- Chain budget checks after the build in CI (`build && check`)
- Verify the distDir path passed to the script
- Avoid cleaning dist/ without rebuilding
When it happens
Trigger: Calling initialDashboardAssetNames or deferredDashboardAppDependencies with a distDir where dist/dashboard.html does not exist (build not run, wrong distDir passed, build output cleaned) or is not readable (permissions).
Common situations: CI runs bundle-budget checks before `npm run build:dashboard`; developer checks out a fresh clone and runs the budget script directly; dist/ was wiped by `clean` but not rebuilt; an incorrect --dist argument points at an empty directory.
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 dashboard entry ${entryPath}: ${error.message}
- ${stale.map((output) => output.relativePath).join(' and ')}
- no initial JS assets referenced by ${dashboardPath} — run: $
- no module entry script in ${dashboardPath} — run: ${BUILD_CO
- Sentry returned 403 for the issues endpoint. A release-scope
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/d3626c33b80c23c0.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/bundle-budgets.mjs:167
/** '/assets/main-x.js', 'assets/main-x.js?v=1' -> 'main-x.js'; null outside assets/. */
function assetFileNameFromUrl(url) {
const path = url.split(/[?#]/, 1)[0];
const marker = path.lastIndexOf('/assets/');
const fileName = marker >= 0
? path.slice(marker + '/assets/'.length)
: path.startsWith('assets/')
? path.slice('assets/'.length)
: null;
return fileName && !fileName.includes('/') ? fileName : null;
}
function readDashboardHtml(distDir) {
const dashboardPath = join(distDir, 'dashboard.html');
try {
return { dashboardPath, html: readFileSync(dashboardPath, 'utf8') };
} catch (error) {
throw new Error(`cannot read ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}: ${error.message}`);
}
}
export function initialDashboardAssetNames(distDir) {
const { dashboardPath, html } = readDashboardHtml(distDir);
const assets = new Set();
for (const match of html.matchAll(/(?:src|href)=["']([^"']+\.js(?:[?#][^"']*)?)["']/gi)) {
const fileName = assetFileNameFromUrl(match[1]);
if (fileName) assets.add(fileName);
}
if (assets.size === 0) {
throw new Error(`no initial JS assets referenced by ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}`);
}
return [...assets].sort();
}
/**
* The asset files Vite preloads for the dashboard entry's deferredView on GitHub (pinned to 7d06c8633d)