Skip to content

fix: preserve app-defined HTTP statuses in responses - #788

Open
kossnocorp wants to merge 6 commits into
mainfrom
fix/784-error-codes
Open

kossnocorp wants to merge 6 commits into
mainfrom
fix/784-error-codes

Conversation

@kossnocorp

@kossnocorp kossnocorp commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

The PR closes #784.

The changes:

  1. Preserve app-defined HTTP statuses when rendering pages

    Previously, Void could replace the loader's status with 200 despite c.status(503):

    // pages/maintenance.server.ts
    import { defineHandler } from 'void/handler';
    
    export const loader = defineHandler((c) => {
      c.status(503);
      c.header('Retry-After', '120');
    
      return { message: 'Down for maintenance' };
    });

    The page now renders with HTTP 503 for both document loads and client navigation. This also works when middleware sets the status, with validated loaders, and when the page streams deferred props.

  2. Render expected loader failures through page error boundaries

    An example of the app checking the user account state:

    // pages/account.server.ts
    import { HTTPException } from 'hono/http-exception';
    import { defineHandler } from 'void/handler';
    import { requireAuth } from 'void/auth';
    
    export const loader = defineHandler(async (c) => {
      const user = requireAuth(c);
    
      const response = await fetch(
        `https://accounts.example.com/users/${encodeURIComponent(user.id)}`,
      );
    
      if (response.status === 410) {
        throw new HTTPException(410, {
          message: 'This account has been permanently deleted',
        });
      }
    
      if (!response.ok) {
        throw new HTTPException(503, {
          message: 'Account details are temporarily unavailable',
        });
      }
    
      return { account: await response.json() };
    });

    Previously, these exceptions returned plain text pages even when the app defined an _error component. Client navigation fell back to a document load, replacing the application and its layouts.

    Now, response-less HTTPException render through the nearest page boundary, preserving their status and public message. For example, pages/account/_error can display an account-specific error within the surrounding layouts.

    • 404 retains its _not-found behavior.
    • Redirects, downloads, and explicit responses retain their existing behavior.
    • Exceptions carrying a custom res retain their explicit response behavior.
    • Ordinary unexpected errors still use generic production messages.
  3. Render application-middleware HTTP failures through the root boundary

    // middleware/maintenance.ts
    import { HTTPException } from 'hono/http-exception';
    import { defineMiddleware } from 'void/handler';
    
    export default defineMiddleware(async (c, next) => {
      if (c.req.path.startsWith('/checkout')) {
        c.header('Retry-After', '120');
    
        throw new HTTPException(503, {
          message: 'Checkout is temporarily unavailable.',
        });
      }
    
      await next();
    });

    Previously, this returned plain text and bypassed the app's root _error component.

    Now, page GET/HEAD requests render the root error boundary with HTTP 503 and the supplied message, without running the page loader. Client navigation preserves the root layout instead of replacing the document.

    Exceptions from handler middleware use the nearest page boundary, like loader exceptions.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://fix-784-error-codes-void-cloud.voidzero-docs.workers.dev (commit 0b9b5de)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://af30e9c0-void-cloud.voidzero-docs.workers.dev 0b9b5de 2026-11-13T10:41:10.433Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://b2762d95-void-cloud.voidzero-docs.workers.dev 481a80a 2026-11-13T10:38:04.696Z Visit the dashboard ↗
  • Build: Failed ❌

View logs ↗
e49f0f4 2026-11-13T10:34:34.203Z View logs ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://1ce7b51d-void-cloud.voidzero-docs.workers.dev e9c4d68 2026-11-13T10:01:55.837Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://3ef343ed-void-cloud.voidzero-docs.workers.dev 0ea1130 2026-11-12T05:53:12.061Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://731fbdd3-void-cloud.voidzero-docs.workers.dev e73d078 2026-11-11T10:29:15.711Z Visit the dashboard ↗

@kossnocorp
kossnocorp marked this pull request as ready for review November 13, 2026 10:01
@kossnocorp
kossnocorp requested a review from a team as a code owner November 13, 2026 10:01
@Brooooooklyn

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-13T10:04:43.842216Z e9c4d68 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: e9c4d684bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

This branch has not been deployed

No deployments
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.

A page can only answer 200, 404 or 500

2 participants