SDK packaging: malformed published version strings and floating/orphaned dist-tags in SDK sources and example apps
@KevinDavilaDotCMS is already working on this.
Since Sep 4, 2026.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Problem Statement
Two related packaging defects in the @dotcms/* SDK. All claims below were reproduced locally against the live npm registry; the observed behaviour is recorded per package manager because it differs.
Defect A — malformed version strings in published packages (affects current latest)
@dotcms/client@26.8.3-1 and its siblings are published with a version string that is invalid semver and does not match the version the registry advertises:
| Source | Value |
|---|---|
Registry metadata for @dotcms/client@26.8.3-1 |
26.8.3-1 |
The same package's tarball-internal package.json version |
26.08.03-01 |
@dotcms/react@26.8.3-1 → dependencies["@dotcms/client"] |
26.08.03-01 |
26.08.03-01 has leading zeros in its numeric identifiers, so it is not valid semver, and no such version exists on npm. npm normalises the registry version field on publish, but it does not normalise the tarball contents or dependency range strings, so the malformed value survives into what customers install.
Observed consequences:
- Anything reading the installed package reports a nonexistent version.
require('@dotcms/client/package.json').versionreturns26.08.03-01. This affects SBOM/licence scanners, vulnerability tooling, bundler metadata and release tagging. - With yarn, the nested copy on disk literally reports
26.08.03-01, so the installed tree cannot be mapped back to a published release. - Resolution currently succeeds only because npm and pnpm apply loose-mode semver coercion. I verified npm 11 and pnpm 11 both resolve it today. Any consumer or resolver using strict semver parsing would fail. This is a latent break, not a current one.
This is present on the newest published packages, so it is a live defect rather than a historical one.
Defect B — floating and orphaned dist-tags in source and examples
B1. SDK library sources still declare "latest" in dependencies. On main:
| File | Field | Value |
|---|---|---|
core-web/libs/sdk/react/package.json |
dependencies |
"@dotcms/client": "latest", "@dotcms/uve": "latest" |
core-web/libs/sdk/angular/package.json |
dependencies |
"@dotcms/client": "latest", "@dotcms/uve": "latest" |
core-web/libs/sdk/experiments/package.json |
peerDependencies |
all four @dotcms/* at "latest" |
core-web/bump-sdk-versions.js only rewrites peerDependencies for SDK libs (updatePeerDependencies) and dependencies for examples (updateDependenciesInExamples). It never rewrites the SDK libs' own dependencies. The current release pipeline masks this by injecting an exact pin at publish time, but the source is still wrong, and the entire published 1.x line, 1.0.6 (2025-09-04) through 1.7.0 (2026-07-13), shipped with "@dotcms/client": "latest".
The customer-facing effect is package-manager dependent. Reproduced with a manifest pinning @dotcms/client, @dotcms/react, @dotcms/uve, @dotcms/types all at 1.2.0:
| Resolver | Result with the pin alone | Affected |
|---|---|---|
| npm 11 | dedupes react's "latest" spec down to the root 1.2.0 |
No |
| yarn 1.22 | installs a second copy at node_modules/@dotcms/react/node_modules/@dotcms/client, reporting 26.08.03-01 |
Yes |
| pnpm 11 | keeps both copies; @dotcms/react's symlink points at @dotcms+client@26.8.3-1 |
Yes |
So on yarn and pnpm a customer's explicit version pin is silently overridden, and @dotcms/react imports from @dotcms/client at runtime (it references buildPageQuery / createDotCMSClient), so react's code path uses the wrong client. npm users are not affected. Since npm immutability means the 1.x tarballs can never be corrected, this is permanent for the version range support recommends for older servers.
Note --legacy-peer-deps is not a mitigation: the "latest" is in dependencies, which that flag does not affect.
B2. Example apps pin floating dist-tags, and two pin an orphaned tag. On main:
| Example | Pinned tag | Resolves to |
|---|---|---|
examples/nextjs |
next |
26.7.27-1-next.2448, frozen 2026-07-29 |
examples/vuejs |
next |
26.7.27-1-next.2448, frozen 2026-07-29 |
examples/angular |
latest |
26.8.3-1, floats forever |
examples/astro |
latest |
26.8.3-1, floats forever |
.github/workflows/cicd_release-sdk.yml states in its header that it publishes "to the latest tag only" and that there is "no @next". The next dist-tag is therefore orphaned: frozen at a pre-release build with nothing updating it. Every customer who scaffolds the documented way receives a stale dev/QA pre-release, which is not a supported configuration:
npx create-next-app my-dotcms-app --example https://github.com/dotCMS/core/tree/main/examples/nextjs
The latest pins are a different failure: they float ahead of the customer's server, producing the recurring FieldUndefined GraphQL skew tickets.
B3. Examples on LTS release branches pin "latest". examples/nextjs/package.json on release-25.07.10_lts_v12 and _v16 pins "latest" for all five packages, resolving today to 26.8.3-1. The LTS-branch example therefore fails against its own LTS server, removing the last working escape hatch for LTS customers.
Customer impact
Helpdesk #38677 (25.07.10 LTS) is live. The customer scaffolded from the main example and got a build whose hardcoded DotCMSPage GraphQL fragment requests numberContents, styleEditorSchemas, lockedBy, lockedByName and layout metadata, none of which exist on their server. They reported trying "all available versions" without success, which B2 explains: the scaffold kept handing them the next tag. Prior instances of the same class: #36678, #37710, #38038.
The SDK's DotCMSPage fragment field list is hardcoded in buildPageQuery, and the graphql.page option only appends a ClientPage fragment, so customers cannot trim the query as a workaround. Pinning is the only mitigation, which is what makes B1 and B2 severe.
Steps to Reproduce
Defect A — version string mismatch:
curl -s https://registry.npmjs.org/@dotcms/client/26.8.3-1 | jq -r .version→26.8.3-1- Download and extract that same tarball, then read its
package.json→"version": "26.08.03-01" curl -s https://registry.npmjs.org/@dotcms/react/26.8.3-1 | jq -r '.dependencies["@dotcms/client"]'→26.08.03-01- Confirm no such version is published: it is absent from the
versionsmap ofhttps://registry.npmjs.org/@dotcms/client
Defect B1 — a customer pin is silently overridden (yarn and pnpm only):
mkdir t && cd t
cat > package.json <<'JSON'
{"name":"t","version":"1.0.0","private":true,
"dependencies":{"@dotcms/client":"1.2.0","@dotcms/react":"1.2.0",
"@dotcms/uve":"1.2.0","@dotcms/types":"1.2.0"}}
JSON
- With yarn:
yarn install, then checknode_modules/@dotcms/react/node_modules/@dotcms/client/package.json→ a second copy exists, reporting26.08.03-01 - With pnpm:
pnpm install, thenls -l node_modules/.pnpm/@dotcms+react@1.2.0*/node_modules/@dotcms/client→ symlink points at@dotcms+client@26.8.3-1 - With npm:
npm ls @dotcms/client --all→ deduped to1.2.0; not affected
Defect B2 — the scaffold delivers an orphaned pre-release:
npx create-next-app my-app --example https://github.com/dotCMS/core/tree/main/examples/nextjscd my-app && npm install && npm ls @dotcms/client- Observe
26.7.27-1-next.2448, a pre-release frozen on 2026-07-29, rather than the current26.8.3-1
Expected: a scaffolded example installs a published, supported release matching the branch it came from; a customer's explicit pin is honoured on every package manager; and an installed package reports the version it was published as.
Actual: the scaffold installs an orphaned pre-release, pins are overridden on yarn and pnpm, and installed packages report a nonexistent version.
Acceptance Criteria
Defect A — version strings
- The release pipeline writes release versions in a form that is valid semver and identical to what the registry advertises (
26.8.3-1, not26.08.03-01) - For a newly published package, the tarball-internal
package.jsonversionmatches the registry metadataversionexactly - Injected
@dotcms/*dependency pins use that same exact string - Resolution no longer depends on loose-mode semver coercion; a strict semver parse of every published
@dotcms/*version and internal dependency range succeeds
Defect B — floating tags
- No
core-web/libs/sdk/*/package.jsondeclares a floating specifier (latest,next,*) for an@dotcms/*entry independenciesorpeerDependencies - The release pipeline rewrites
dependencies, not onlypeerDependencies, for SDK libs;bump-sdk-versions.jsis updated or retired accordingly (itsbumpVersionregex only accepts-alpha.Nand is already dead code for the CalVer scheme) -
examples/nextjs,examples/vuejs,examples/angular,examples/astroonmainpin exact published versions instead ofnextorlatest, and the pipeline updates those pins when publishing - The
nextdist-tag is either resumed by the pipeline or removed from npm, so no documented path resolves to an orphaned tag - Examples on maintained LTS branches pin a version compatible with that LTS line (for
release-25.07.10_lts*this is1.2.0, the newest release whose page query validates against that schema) - CI fails the build if any
core-web/libs/sdk/*/package.jsonorexamples/*/package.jsonreintroduces a floating@dotcms/*specifier
Verification
- Scaffolding each example from
main, installing, and runningnpm ls @dotcms/clientyields exactly one copy at the expected published release - Scaffolding
examples/nextjsfromrelease-25.07.10_lts_v16against a 25.07.10 LTS server renders a page with noFieldUndefinederrors - Installing a pinned
@dotcms/reactunder npm, yarn and pnpm yields exactly one@dotcms/clientat the pinned version in all three
Follow-up for support docs (published 1.x cannot be fixed retroactively): record that any recommendation to pin a 1.x version must include overrides (npm), resolutions (yarn) or pnpm-workspace.yaml overrides (pnpm 10+), plus a verification step. Note specifically that pnpm.overrides inside package.json is silently ignored by pnpm 11 — I verified it does not take effect and the override must go in pnpm-workspace.yaml.
dotCMS Version
- Defect A: current published packages,
26.7.21-1onward (verified on26.8.3-1) - Defect B1: source on
main; published@dotcms/reactand@dotcms/angular1.0.6through1.7.0 - Defect B2/B3:
main,release-25.07.10_lts_v12,release-25.07.10_lts_v16 - Reported against server
25.07.10 LTS; the packaging defects themselves are server-version independent - Verified with npm 11, yarn 1.22.21, pnpm 11.7.0
Severity
High - Major functionality broken
Links
- Freshdesk ticket #38677 (live, 25.07.10 LTS)
- Freshdesk ticket #36678 (same class,
metadata) - Freshdesk ticket #37710 (same class,
styleEditorSchemas) - Freshdesk ticket #38038 (same class, SDK too old)
- Slack: support thread
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.