Repository navigation
Temporal does not compile with shared ICU or no ICU #62676
Description
Activity
- addedv8 engineIssues and PRs related to the V8 dependency.Issues and PRs related to the V8 dependency.
on Apr 10, 2026 - added a commit that references this issue
on Apr 17, 2026 - added a commit that references this issue
on May 5, 2026 Has this issue been resolved? Does it need to remain open?
It has not been resolved, no action have been taken
Reacted by James M Snell, dontwanttothink and Virgil MingI opened a V8-side CL intended to fix this at the source instead of carrying a Node-specific V8 patch:
https://chromium-review.googlesource.com/c/v8/v8/+/7831715
Design:
- stop using ICU's private
udatamem.h/UDataMemory::lengthpath when Temporal + i18n is enabled; - always generate and link the existing
zoneinfo64_static_datablob when Temporal is enabled; - make the i18n and non-i18n Temporal timezone provider use the same baked
zoneinfo64.resdata path.
Expected effect:
--with-intl=system-icuno longer depends on private ICU headers from the system ICU package;--without-intl/ no-ICU Temporal builds still get the generated zoneinfo64 data linked in;- embedders using system/shared ICU do not need ICU private headers or private ABI details just to load Temporal timezone data.
This is upstream V8 work, so Node still needs to wait for V8 review/landing and then consume it via a V8 roll/backport, including any generated build file updates needed on the Node side. Until then, downstreams may still need temporary packaging workarounds. The intent is to replace the earlier
__has_includestyle workaround with a cleaner design that removes the private ICU dependency entirely.- stop using ICU's private
Update after V8 review feedback on the upstream CL:
https://chromium-review.googlesource.com/c/v8/v8/+/7831715
V8's position is that using ICU4C data for
zoneinfo64.resis deliberate, because bundled ICU already ships that timezone data and V8 does not want to duplicate it in normal i18n builds.Given that, I think the downstream fix should not be to silently disable Temporal for packagers. If the current V8 Temporal implementation requires the bundled/full ICU source path, Node's build should make that requirement clear and downstreams should pin to the supported upstream ICU source/version at build time.
Concretely, for distributions that want to ship Node 26 with Temporal enabled, the viable packaging route is:
./configure \ --with-intl=full-icu \ --with-icu-source=/path/to/node-pinned-icu-source
That keeps the build aligned with the ICU version expected by Node/V8, avoids the unsupported system/shared ICU Temporal path, and produces a complete Node package instead of a build where a headline Node 26 feature is trimmed out.
It would still be useful for Node's configure behavior to make this sharper: if
--with-intl=system-icuor--without-intlcannot support Temporal with the current V8 dependency, the build should clearly direct packagers to the pinned full-ICU source route rather than just producing a Node binary with Temporal disabled by default.Building V8 should not require outside private headers to build, period. This is a breaking of the practice of public vs. private APIs. You should be able to build node using existing system libraries through public APIs.
Reacted by Danny McClanahanI agree with this. Requiring external/system ICU consumers to include
udatamem.hcrosses the public/private API boundary.After looking at ICU's data APIs, I think the deeper gap may be in ICU's public API surface:
- public
udata_open()can open the ICU data item; - public
udata_getMemory()returns the actual data payload; - public
udata_getInfo()returns metadata from the data header; - but there does not appear to be a public API that returns a stable
(raw data item including the ICU data header, exact length)view.
That is exactly the shape V8/
temporal_rscurrently wants forzoneinfo64.res: not interpreted ICU resource-bundle access, but the raw.resbinary item including the header, with a usable length.ICU already has internal APIs close to this (
udata_getRawMemory()andudata_getLength()), and the ICU source even notes thatudata_getLength()could be considered for public exposure, but would need stronger semantics for exact lengths in all cases:https://github.com/unicode-org/icu/blob/main/icu4c/source/common/udatamem.cpp
So I think the path that would satisfy all sides is probably:
- V8 should not duplicate timezone data when bundled/full ICU already ships
zoneinfo64.res. - Node/system-ICU builds should not be forced to use ICU private headers.
- ICU should expose a public, stable data-item export/view API that lets embedders get a raw ICU data item plus length when they intentionally need to pass that binary data to another engine such as
temporal_rs.
Until such an ICU API exists, downstream packagers still need a practical build path. For Node 26, that likely means using the supported full-ICU source route for Temporal-enabled packages rather than silently disabling Temporal. But long term, a standardized ICU data export API would be cleaner than either duplicating timezone data in V8 or requiring private ICU headers.
- public
Follow-up with the ICU upstream tracking link:
- ICU Jira: https://unicode-org.atlassian.net/browse/ICU-23400
- ICU design-list proposal has also been sent to
icu-design@unicode.org.
My current read of the long-term direction is:
- V8/Chromium should be able to keep the current no-duplicate-data design when ICU already ships
zoneinfo64.res. - Node and other external/system-ICU embedders should not need ICU private headers such as
udatamem.hto build a public Node release. - ICU should expose a stable public data-item view/export API that can return the raw ICU data item plus exact length for cases like
temporal_rsthat intentionally need the raw.resbytes.
Until that ICU API exists, the practical V8-side short-term fix seems to be an explicit V8 build option for the Temporal zoneinfo64 provider: default to the ICU-backed path for Chromium/bundled ICU builds, and let embedders that cannot use private ICU headers disable that path and use baked
zoneinfo64data instead. That is better than silently dropping Temporal from Node builds, and cleaner than relying on__has_includeto guess packaging policy.Is there any chance that you could fix this in a minor release of node 26? That is, assuming that you can get ICU and V8 to fix it.
My concern is that node 26 is slated to become an LTS release.
This issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.Reacted by dontwanttothink and Igor Mahov- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Aug 9, 2026 34 remaining items
- added 8 commits that reference this issue
on Sep 30, 2026 - added a commit that references this issue
on Oct 4, 2026 - added a commit that references this issue
on Oct 5, 2026 - added a commit that references this issue
on Oct 7, 2026
When Node.js is configured with
--with-intl=none(or--without-intl) or--with-intl=system-icuthe build fails when Temporal is enabled.e.g.
--with-intl=system-icu: https://ci.nodejs.org/job/node-test-commit-linux-containered/nodes=ubuntu2404_sharedlibs_icu_x64/55537/console--without-intlhttps://ci.nodejs.org/job/node-test-commit-linux-containered/nodes=ubuntu2404_sharedlibs_withoutintl_x64/55537/consoleThe first issue (with
--with-intl=system-icu) stems from V8 using a private header file from ICU. In #62508, this is being worked around by temporarily patching V8 with https://github.com/nodejs/node/pull/62508/files#diff-89a9a4423f9b83142d44bfb376f2c56ffff396ee1ef98c4930a61d5ed9732c7f. Unfortunately applying that in #61806 breaksparallel/test-temporal-with-zoneinfoin the default (no--with-intl=...specified) case.e.g. https://github.com/nodejs/node/actions/runs/24165429332/job/70525857573?pr=61806#step:9:6040
Also ideally we don't want to be carrying patches on top of V8 as much as possible, so would prefer something patched upstream in V8 if possible.
Refs: #61806 (comment)