Skip to content

Improve error handling across build pipeline #414

@scode2277

Description

@scode2277

Problem

When vocs build fails, it's extremely difficult to diagnose what went wrong. Errors are either silently swallowed, missing file path / line context, or immediately kill the process while discarding diagnostic info that Vite/Rollup already has.

This makes debugging build failures a trial-and-error process of commenting out pages until the broken one is found.

Current behavior

1. src/vite/build.ts: Prerender and scripts phases silently swallow errors

The catch blocks at lines ~59-61 (prerender) and ~82-84 (scripts) call the lifecycle hook but do not re-throw. When used without CLI hooks (e.g. programmatic API), the build silently continues after failure:

// prerender phase: error is caught but never re-thrown
catch (error) {
  hooks?.onPrerenderEnd?.({ error: error as Error })
  // ← build continues as if nothing happened
}

Same pattern for the scripts phase.

2. src/vite/prerender.tsx: No per-route error handling

The prerender loop has no try/catch per route. If a single page fails to render, the entire prerender aborts with no indication of which route caused the failure:

for (const route of routes) {
  const body = await mod.prerender(route)  // ← one bad page kills everything
  // ...
}

3. src/cli/commands/build.ts: Error details are discarded

The CLI hooks only print error.message and immediately process.exit(1), discarding the stack trace, source file path, and line/column info that Vite/Rollup errors carry:

onBundleEnd({ error }) {
  if (error) {
    spinner.client.fail(`bundles failed to build: ${error.message}`)
    process.exit(1)  // ← error.id, error.loc, error.frame, error.stack all lost
  }
}

Vite/Rollup errors typically include error.id (file path), error.loc (line/column), error.frame (code snippet), and error.plugin, none of which are surfaced.

4. src/vite/plugins/mdx.ts: No error wrapping around MDX compilation

The @mdx-js/rollup plugin is passed through with zero wrapping. MDX syntax errors (unclosed tags, invalid JSX, bad frontmatter) produce errors from micromark with file: '' (empty string), so the source file path is lost entirely. The error shape looks like:

{
  line: 28,
  column: 2,
  file: '',           // ← empty, useless
  reason: 'Unexpected end of file before name...',
  source: 'micromark-extension-mdx-jsx',
  ruleId: 'unexpected-eof'
}

The file path is available in the Rollup transform hook's id parameter but is never attached to the error.

5. src/vite/plugins/dev.tsx: Dev server SSR middleware has no catch block

The try { ... } finally { next() } pattern means SSR render errors crash the dev server instead of showing Vite's error overlay. Related: #163.

Expected behavior

  • Build errors should include the file path, line/column (when available), and a readable error message
  • Prerender/scripts phase errors should not be silently swallowed
  • Dev server should show an error overlay instead of crashing
  • The CLI should print Vite/Rollup error properties (error.id, error.loc, error.frame) when available

Reproduction

  1. Create any MDX page with a syntax error, e.g. a lone < on a line:
    # Test page
    
    Some content
    
    <
  2. Run vocs build
  3. Output shows a huge output, too generic and not understandable by both human and AI scan
  4. The only way to find the broken file is to binary-search by removing pages and retest the build

Environment

  • vocs: 1.2.2 (also verified against 1.4.1 source - same issues exist)

I'm happy to submit a PR addressing these.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions