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

  1. Run a fresh full BUILD_COMMANDS.dashboard build so HTML and assets/ are regenerated together
  2. Confirm dist/assets/<entryName>.js exists (compare with the src in dashboard.html)
  3. Wipe dist/ and rebuild if stale hashed chunks linger from an earlier build
  4. 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

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


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)