Skip to content

docs(elysia): caution callout for parse: 'none' refactor footgun#1281

Open
alexkahndev wants to merge 1 commit intopingdotgg:mainfrom
alexkahndev:docs/elysia-parse-none
Open

docs(elysia): caution callout for parse: 'none' refactor footgun#1281
alexkahndev wants to merge 1 commit intopingdotgg:mainfrom
alexkahndev:docs/elysia-parse-none

Conversation

@alexkahndev
Copy link
Copy Markdown

@alexkahndev alexkahndev commented May 1, 2026

Summary

The Elysia example currently uses (ev) => handlers(ev.request), which works fine. But the moment a user refactors either route to the more idiomatic destructured form ({ request }) => handlers(request), the route silently breaks: Elysia's static analyzer (sucrose) flips inference.body = true, Elysia compiles in a request.json() before the handler runs, and UploadThing's handler receives a consumed stream — surfacing as an empty-body 400 at the client with no actionable log.

This PR keeps the working example untouched and adds:

  • A <Note> callout in the Elysia docs section explaining the gotcha and showing the { parse: "none" } opt-out for users who do refactor.
  • An inline comment in examples/backend-adapters/server/src/elysia.ts noting why the ev.request shape is intentional.

No package changes; no changeset (mirrors the docs-only pattern of #976).

Why this is worth flagging

The failure mode is genuinely hard to debug:

  1. The error has no log on the server side — UT silently returns 400.
  2. The response carries no x-uploadthing-version header (it never reached UT's handler), so it isn't obviously a UT issue.
  3. The fix isn't documented in either UT or Elysia by name. Elysia has a docs page on explicit parsers, but it doesn't explain that an analyzer-driven inference.body = true is what triggers them in the first place.

Most Elysia users naturally write ({ request }) => over (ev) => — it's the recommended style across the rest of the Elysia ecosystem and docs. Without this callout, copy-pasting the docs example then "cleaning it up" silently breaks uploads.

Root cause (for the record)

node_modules/elysia/dist/sucrose.mjs lines 179–198. The relevant regexes:

captureFunction = /\w\((?:.*?)?<param>(?:.*?)?\)/gs
exactParameter  = /<param>(,|\))/gs

For (ev) => handlers(ev.request):

  • mainParameter = "ev", body = "handlers(ev.request)"
  • exactParameter requires ev, or ev). Body has ev. → no match.
  • inference.body stays false → Elysia doesn't pre-parse → UT works.

For ({ request }) => handlers(request):

  • mainParameter = "request", body = "handlers(request)"
  • exactParameter matches request).
  • All nine inference flags get flipped (defensive overestimate) including body.
  • hasBody becomes true at compose.mjs:258 → Elysia injects request.json() → stream consumed → UT errors.

References

Summary by CodeRabbit

  • Documentation
    • Enhanced Elysia backend adapter documentation with clarification on handler configuration to prevent request body parsing issues.
    • Added guidance on proper route configuration options for .get/.post definitions.
    • Improved code examples with explanatory comments on request stream handling patterns.

The current example uses `(ev) => handlers(ev.request)`, which works
because Elysia's static analyzer (sucrose) doesn't recognize the
property-access shape as body access. If a user refactors to the more
idiomatic destructured form `({ request }) => handlers(request)`, the
analyzer flips `inference.body = true`, Elysia compiles in a
`request.json()` call, and UT's handler receives a consumed stream —
surfacing as a silent empty-body 400.

This change keeps the original example untouched and adds:
- A `<Note>` callout in the docs page explaining the gotcha and showing
  the `{ parse: "none" }` workaround for users who do refactor.
- An inline comment in the runnable example noting why the handler
  shape is intentional.

`parse: 'none'` is the upstream-recommended fix per elysiajs/elysia#1252
and the same option Elysia uses internally for `.mount()`.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 1, 2026

⚠️ No Changeset found

Latest commit: 7743451

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link
Copy Markdown

vercel Bot commented May 1, 2026

Someone is attempting to deploy a commit to the Ping Labs Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f511eb71-8629-4313-af6a-4161bc8e5734

📥 Commits

Reviewing files that changed from the base of the PR and between 720849f and 7743451.

📒 Files selected for processing (2)
  • docs/src/app/(docs)/backend-adapters/fetch/page.mdx
  • examples/backend-adapters/server/src/elysia.ts

Walkthrough

Documentation additions clarifying an Elysia handler-shape pitfall where destructured request parameters cause auto-parsing of request bodies, preventing UploadThing from reading the stream. Includes a code example showing the fix with { parse: "none" } and a comment explaining the pattern used in the example server.

Changes

Cohort / File(s) Summary
Elysia Backend Adapter Documentation
docs/src/app/(docs)/backend-adapters/fetch/page.mdx
Adds a note documenting the pitfall where Elysia auto-parses destructured request parameters, causing UploadThing to receive an empty body. Provides explicit fix using .get/.post route definitions with { parse: "none" } option and references upstream issue.
Elysia Server Example
examples/backend-adapters/server/src/elysia.ts
Adds explanatory comment clarifying why /api/uploadthing route handlers use (ev) => handler(ev.request) pattern to prevent Elysia's static analyzer from triggering pre-parsing behavior.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: documenting a Elysia handler refactoring pitfall with the parse: 'none' solution.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 1, 2026

Greptile Summary

This PR adds a <Note> callout to the Elysia section of the backend-adapters docs explaining a silent breakage that occurs when users refactor (ev) => handlers(ev.request) to the more idiomatic ({ request }) => handlers(request), and adds a matching inline comment in the example file. The explanation is technically accurate, the { parse: "none" } fix is the canonical upstream recommendation, and both the docs example and the <Note> component usage are consistent with the rest of the file.

Confidence Score: 5/5

Safe to merge — documentation-only change with no functional modifications.

Both changed files are purely additive docs/comment changes. The technical explanation is accurate, the { parse: "none" } fix matches upstream recommendations, and the <Note> component usage is consistent with existing patterns in the file. No code paths are modified.

No files require special attention.

Important Files Changed

Filename Overview
docs/src/app/(docs)/backend-adapters/fetch/page.mdx Adds a <Note> callout after the Elysia code block documenting the static-analyzer footgun and the { parse: "none" } fix; matches the existing <Note> component pattern used throughout the file.
examples/backend-adapters/server/src/elysia.ts Adds an explanatory comment above the Elysia route definitions clarifying why the ev.request shape is intentional; no functional changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Elysia route receives request] --> B{Handler shape?}
    B -->|ev handler| C[sucrose: mainParameter is ev\nbody has ev dot - no match]
    B -->|destructured handler| D[sucrose: mainParameter is request\nbody has request - matches]
    C --> E[inference.body = false\nNo pre-parse injected]
    D --> F[inference.body = true\nAll 9 inference flags flipped]
    E --> G[UploadThing handler\nreceives intact stream]
    F --> H[Elysia injects request.json\nStream consumed before handler]
    H --> I[UploadThing gets empty body\nSilent 400 at client]
    D --> J{Fix: add third arg\nparse none}
    J --> G
Loading

Reviews (1): Last reviewed commit: "docs(elysia): caution callout for parse:..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant