Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[Bug]: `shopify hydrogen dev` exits before listening when the npm registry is unreachable (p-cancelable onCancel-after-settle in latest-version chunk)

未关闭
#8,553 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
48/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
领域
cli

调研方向

从 dist/chunk-GW4JHUIA.js 中的 getLatestNPMPackageVersion 开始,跟踪它在 dist/chunk-IF6EYTHG.js 中的调用方 checkForNewVersionOnCLI,包括 dist/chunk-IF6EYTHG.js 中的 Hydrogen 路径。在 npm-registry 访问被阻止的情况下重现;当 shopify hydrogen dev 保持运行并在没有未捕获的 p-cancelable 错误的情况下到达本地监听输出时,即表示完成。

由索引模型根据 Issue 内容生成。

描述

Please confirm that you have:
  • Searched existing issues to see if your issue is a duplicate.
  • Reproduced the issue in the latest CLI version.
In which of these areas are you experiencing a problem?

Hydrogen custom storefront

Expected behavior

shopify hydrogen dev starts the dev server. The startup "is there a newer version?" check is a
courtesy; if the npm registry is unreachable it should degrade to a debug log and the server should
still come up.

Actual behavior

When the npm registry is unreachable, shopify hydrogen dev exits 1 before the dev server ever
listens
. No ➜ Local: line is printed. The process dies with p-cancelable's internal invariant:

> shopify hydrogen dev --codegen --port "$PORT"

The `envFile` option is deprecated, please use `envDir: false` instead.
[vite] (ssr) Re-optimizing dependencies because vite config has changed
[vite] (client) Re-optimizing dependencies because vite config has changed
Error: The `onCancel` handler was attached after the promise settled.
    at o (node_modules/@shopify/cli/dist/latest-version-LDWU5F7A.js:11:17603)
    at d (node_modules/@shopify/cli/dist/latest-version-LDWU5F7A.js:19:47843)
    at t.<anonymous> (node_modules/@shopify/cli/dist/latest-version-LDWU5F7A.js:19:49069)
    at t.wrapper (node:events:639:12)
    at t.emit (node:events:514:20)
    at t.emit (node:domain:473:12)
    at node_modules/@shopify/cli/dist/latest-version-LDWU5F7A.js:19:37968
    at runNextTicks (node:internal/process/task_queues:65:5)
    at processTimers (node:internal/timers:615:9)

This is a hard startup failure, not a degraded notification.

Reproduction steps
  1. Scaffold or use any Hydrogen storefront; npm ci with network so node_modules is complete.
  2. Remove npm-registry reachability. Any of these reproduce it: firewall DROP, firewall
    REJECT/ECONNREFUSED, or refusing DNS.
  3. npm run dev (i.e. shopify hydrogen dev).

Exits 1 with the trace above. Reproduced on Node 26.8.2 / npm 11.19.1, Debian trixie (node:26-slim),
linux/arm64 and linux/amd64.

Analysis

From the shipped bundle of 4.7.1:

latest-version-*.js is dynamically imported from exactly one place — getLatestNPMPackageVersion
in dist/chunk-GW4JHUIA.js:

async function ne(e) {                                   // getLatestNPMPackageVersion
  return d(s`Getting the latest version of NPM package: ${c.raw(e)}`),
    y("cmd_all_timing_network_ms")(async () => {
      const { default: n } = await import("./latest-version-LDWU5F7A.js");
      return n(e);
    });
}

whose only caller is checkForNewVersionOnCLI, which already wraps it defensively:

async function Pe(e, n, { cacheExpiryInHours: a = 0 } = {}) {   // checkForNewVersionOnCLI
  const t = async () => (d(s`Checking if there's a version of ${e} newer than ${n}`), ne(e));
  let p;
  try { p = await O(`npm-package-${e}`, t, a * 3600 * 1000); } catch { return; }
  if (p && new SemVer(n).compare(p) < 0) return p;
}

The try/catch cannot help. The thrown error is p-cancelable's guard in its own constructor:

const o = a => {
  if (!this._isPending) throw new Error("The `onCancel` handler was attached after the promise settled.");
  this._cancelHandlers.push(a);
};

and the stack bottoms out in processTimers → runNextTicks, reaching node:domain. So the throw
originates from a timer callback firing after the awaited promise already settled — outside the
await, therefore outside the catch. It escapes as an uncaught exception and terminates the
process. latest-version-*.js contains 22 setTimeout and 1 setInterval.

checkForNewVersionOnCLI has two callers in the bundle: the auto-upgrade path
(dist/chunk-4FI2YBRF.js) and Hydrogen's own version check in dist/chunk-IF6EYTHG.js. The latter
is the one that reaches hydrogen dev, and its only early-outs are a module-level flag and
next/experimental/snapshot version strings.

Notably not workarounds

Each measured, not assumed:

  • CI=1 — no effect. The CI check in versionToAutoUpgrade sits after the lookup and governs a
    different function; the Hydrogen-side caller has no CI guard at all.
  • Refusal vs. black-holing — no effect. With nftables reject with tcp reset returning
    ECONNREFUSED in 3 ms (kernel counters confirmed non-zero after the run), the crash is
    byte-identical to a silent drop. Settle timing is not the variable; a stale timer is.
  • Upgrading the CLI — no effect. dist/latest-version-LDWU5F7A.js is byte-identical
    (sha256 c493bb882df5b786…) across 4.6.1, 4.7.1, 4.8.0, and the 2026-09-14 nightly.
  • Env opt-out — none exists. All 42 SHOPIFY_CLI_* variables in the bundle were inventoried;
    SHOPIFY_CLI_FORCE_AUTO_UPGRADE only forces the upgrade, and autoUpgradeEnabled lives in the
    conf store rather than the environment.
Impact

Any environment that runs a Hydrogen dev server without npm-registry egress cannot start the
storefront at all: CI sandboxes, offline development, and restricted-egress hosting. In our case the
dev server runs under a deliberately locked-down egress policy, so this is unconditional.

Suggested fix

Make the version check unable to reject into the process. Either attach the onCancel handler
synchronously during construction (before any await), or defensively guard the registration:

if (promise.isPending) promise.onCancel(...)

and clear the pending timers when the request settles or aborts. An explicit opt-out
(SHOPIFY_CLI_SKIP_VERSION_CHECK=1) would also let restricted environments avoid the network call
entirely.

Operating System

Debian GNU/Linux 13 (trixie), containerized; reproduced on both arm64 and amd64.

Shopify CLI version

4.7.1 (chunk identical in 4.6.1, 4.8.0, nightly)

Node version

26.8.2

主要语言
TypeScript
星标
750
派生
293
平均合并
3 天 20 小时
30 天内合并 PR
79

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

Shopify/cli 的其他 Issue

查看 Shopify/cli 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。