Skip to content

fix(dev): probe ports through the real Deno runtime, not the dnt shim - #3610

Merged
kojiwakayama merged 1 commit into
mainfrom
fix/dx-20260811-r2-25
Aug 11, 2026
Merged

kojiwakayama merged 1 commit into
mainfrom
fix/dx-20260811-r2-25

Conversation

@kojiwakayama

Copy link
Copy Markdown
Contributor

Symptom

A CLI installed the way the installation guide now tells people to install it —
deno install -gArf npm:veryfront (added by 0d36976 / #3569) — produces a
working veryfront, but veryfront dev dies before printing a URL:

✗ [unknown-error] Unknown/unclassified error

  Detail: Cannot read properties of null (reading 'fd')
  Suggestion: Check logs for more details

build, serve, routes and doctor all succeed under the same install. The
npm-global install of the identical version (npm i -g veryfront@0.1.1229) runs
dev fine, so the defect is specific to running the published package on Deno.

Root cause

Recovered by unwrapping the boundary error against published 0.1.1229:

TypeError: Cannot read properties of null (reading 'fd')
    at Object.listen (node_modules/@deno/shim-deno/dist/deno/stable/functions/listen.js:44:64)
    at isPortAvailable (node_modules/veryfront/esm/cli/commands/dev/port-fallback.js:38:26)
    at clearLocalCachesIfPortFree (node_modules/veryfront/esm/cli/commands/dev/command.js:95:16)

isPortAvailable branched on isDeno and then called Deno.listen. dnt
rewrites every bare Deno. call site in the published npm package into
@deno/shim-deno — the emitted line really is dntShim.Deno.listen(...) — and
that shim's Node-backed listen() reads server._handle.fd, which is null
under Deno's node:net.

The two halves therefore disagreed on a Deno-global install:

  • isDeno is computed from the real global (Reflect.get(globalThis, "Deno")),
    so it was true;
  • the Deno identifier in the same function had been rewritten to the shim.

runtime.ts even documents isDeno as "true if running in the real Deno runtime
rather than a dnt shim" — the constant was right, the call site was not. The
resulting TypeError carries nothing the error registry can match, which is why
the user got unknown-error rather than anything actionable.

port-fallback.js was the only dntShim.Deno reference in the whole dev
command tree, which is exactly why only dev was affected.

Fix

Read the runtime with getDenoRuntime() — the accessor that already exists for
this, used the same way in cli/commands/serve/split-mode.ts and elsewhere. It
resolves the real global through Reflect.get, which dnt leaves alone. Under
Node it returns undefined and the existing node:net path still runs.

Regression test

Deno and the shim are the same object in-repo, so no in-process test can tell
Deno.listen from getDenoRuntime().listen here — the divergence only exists in
the dnt output. The test therefore asserts the invariant over the source dnt
actually rewrites: comment- and string-stripped port-fallback.ts must contain
no bare Deno. call site, and must reach the runtime via getDenoRuntime().

Verified red before the fix, for the right reason (1 offender: Deno.listen),
and green after.

Verified against the published repro

Reproduced first against published 0.1.1229 outside the platform checkout:

DENO_INSTALL_ROOT=/tmp/r2-25-sandbox/d deno install -gArf -n vf25 npm:veryfront@0.1.1229
vf25 init app25 --template minimal
cd app25 && vf25 dev
# -> ✗ [unknown-error] ... Cannot read properties of null (reading 'fd')

Then re-ran the finding's own command with only this change applied to the
published artifact's emitted port-fallback.js:

  ✓ Ready in 834ms
  http://veryfront.me:3000

Notes

No doc change is needed here; the installation guide's deno install -gArf npm:veryfront instruction is correct and this makes it true for dev too.
Separately, #3569 is merged but the live installation page still does not show
the Deno section — that deployment gap is tracked by another finding, not this PR.

`veryfront dev` died immediately under a globally installed CLI
(`deno install -gArf npm:veryfront`) with an unclassified error:

  [unknown-error] Unknown/unclassified error
  Detail: Cannot read properties of null (reading 'fd')

`isPortAvailable` branched on `isDeno` and then called `Deno.listen`. dnt
rewrites every bare `Deno.` call site in the published npm package into
`@deno/shim-deno`, whose Node-backed `listen()` reads `server._handle.fd` -
null under Deno's `node:net`. So on a Deno-global install the runtime check
saw a real Deno and passed, while the call itself reached the shim and threw
a `TypeError` the error registry cannot classify. `build`, `serve`, `routes`
and `doctor` were unaffected because only `dev` probes ports this way.

Read the runtime with `getDenoRuntime()` instead - the accessor that exists
for exactly this. It resolves the real global through `Reflect.get`, which
dnt leaves alone. Under Node it returns undefined and the existing `node:net`
path still runs.

Deno and the shim are the same object in-repo, so the regression test asserts
the invariant over the source dnt actually rewrites.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@kojiwakayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 44 seconds

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2e561d9a-fea0-484b-ba3f-fa3deff37b61

📥 Commits

Reviewing files that changed from the base of the PR and between 64d6850 and 3605ed4.

📒 Files selected for processing (2)
  • cli/commands/dev/port-fallback.test.ts
  • cli/commands/dev/port-fallback.ts

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

@kojiwakayama
kojiwakayama added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit a7ba486 Aug 11, 2026
33 checks passed
@kojiwakayama
kojiwakayama deleted the fix/dx-20260811-r2-25 branch August 11, 2026 21:43
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.

1 participant