Skip to content

fix: report queue options and page settings that Void cannot read - #754

Merged
cpojer merged 1 commit into
voidzero-dev:mainfrom
morinokami:fix/unreadable-export-settings
Nov 9, 2026
Merged

cpojer merged 1 commit into
voidzero-dev:mainfrom
morinokami:fix/unreadable-export-settings

Conversation

@morinokami

Copy link
Copy Markdown
Collaborator

Void reads queue consumer options from the source without running it, and only understands export const name = <literal>. Every other way of exporting the same name is skipped without a message. A queue that shares its options through a module builds and deploys with Cloudflare's defaults:

// queues/_options.ts
export const maxRetries = 0;
export const retryDelay = 30;
// queues/emails.ts
import { defineQueue } from 'void';

export { maxRetries, retryDelay } from './_options';

export default defineQueue(async (batch) => {
  // ...
});

The consumer gets maxRetries 3 and retryDelay 0, so a failing message is retried three times without delay instead of being dropped. The same happens with export lists (export { maxRetries }), let and var, destructuring, and export * from. The queues guide only says "Export named constants".

Page settings are read the same way: revalidate, prerender and ssr in a page's .server.ts, and layout in a page component. There, a computed value is skipped as well: with export const revalidate = 60 * 60, the page falls back to routing.revalidate.

Fix

The shared reader in shared/static-exports.ts now also reports the names a scanner asks about that are exported in a form whose value it cannot read, and whether the module uses export * from. Each scanner decides what to do with them:

  • Queue options in another form fail the build, as computed values already did:
    queue: maxRetries in 'emails.ts' must be declared in the queue file as `export const maxRetries = <integer>`. Re-exported options and other export forms are not read.
    
  • Page settings that cannot be read are still ignored, but print a warning once per file. A hard error would break builds that ship them today, which is also why fix: finish or correct Void features that were advertised but unfinished #433 made layout paths a warning.
  • export * from in a queue file, a page's .server.ts or a page component prints a warning, since Void cannot tell which names it brings in. The check that decides whether to parse a file skips whitespace and comments, so export /* shared */ * from counts too. A queue file that declares all four options, or a page that declares its own layout, gets no warning: its own exports take precedence.
  • In a .server.ts, that warning also names loader, action, actions and getPrerenderPaths. Page method detection doesn't follow export * either, which affects automatic prerendering, action types and the prerender path list.
  • Exports in a Svelte instance script declare component props, so export let layout there is not read as a layout setting and gets no warning. A layout in a later <script module> is still found.

Type-only exports are ignored. Values written as export const name = <literal> are read as before. The cron scanner moves to the new reader without a change in behavior.

The queues, revalidation, Pages overview and layouts guides now say that these values must be literals declared with export const in the file itself.

Behavior change: an app that shares queue options through another module now fails to build until each queue file declares them. Those values were never applied.

Tests

  • packages/void/test/unit/queue-scan.test.ts: re-exports, export lists, a renamed local, let and destructuring fail with the message above. export * from warns once, also with a comment or line breaks between export and *. Type-only exports, and a file that declares all four options beside export *, stay silent.
  • packages/void/test/unit/pages-scan.test.ts: a computed revalidate, non-boolean prerender and ssr, re-exported, renamed, let and destructured settings, unreadable and non-string layouts, and export * in server files and components each warn once and keep the default. Type-only exports and a layout declared beside export * stay silent. A Svelte <script module> or <script context="module"> layout after an instance prop named layout is read, and an instance prop alone gets no warning.

Each of the 21 new error and warning cases fails without this fix.

Verification

  • vp test run: 785 files pass, 1 skipped (16,406 tests pass, 30 skipped).
  • vp run check: 33/33 pass.
  • The React, Vue, Svelte and Solid Pages playgrounds build without new warnings.
  • Not run: void deploy against Cloudflare.

🤖 Generated with Claude Code

Void reads these values from the source without running it, and used to
skip every form other than `export const name = <literal>` silently.

- Queue options exported in another form (re-exports, export lists, let,
  destructuring) now fail the build instead of deploying Cloudflare's
  defaults.
- Page revalidate, prerender, ssr and layout values that cannot be read
  are still ignored, but now print a warning. A hard error would break
  builds that already ship them.
- `export * from` in a queue file, page server file or page component
  prints a warning, including when a comment sits between the tokens.
- Svelte instance-script exports are component props, so they are not
  treated as layout settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cpojer cpojer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@cpojer
cpojer merged commit 73dbf57 into voidzero-dev:main Nov 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants