docker: fix self-build breakage after extension migration#48523
docker: fix self-build breakage after extension migration#48523gbballpack wants to merge 1 commit into
Conversation
d60a0f3 to
5989881
Compare
Greptile SummaryThis PR fixes three interacting bugs that caused self-built Docker images to fail to start after the channel-to-extension migration on Key changes:
Confidence Score: 4/5
|
| @@ -98,6 +112,9 @@ RUN pnpm ui:build | |||
| FROM build AS runtime-assets | |||
| RUN CI=true pnpm prune --prod && \ | |||
| find dist -type f \( -name '*.d.ts' -o -name '*.d.mts' -o -name '*.d.cts' -o -name '*.map' \) -delete | |||
| # Restore self-referencing package link removed by pnpm prune --prod. | |||
| # Required for openclaw/plugin-sdk/* subpath imports at runtime. | |||
| RUN ln -s /app /app/node_modules/openclaw | |||
There was a problem hiding this comment.
Use ln -sf for consistency and idempotency
The rest of the Dockerfile uses ln -sf (line 242: ln -sf /app/openclaw.mjs /usr/local/bin/openclaw), but this line uses plain ln -s. While pnpm prune --prod currently removes the self-referencing symlink, using -f (force) would make this layer idempotent and guard against future pnpm version changes that might leave the symlink in place — causing the build to fail with "File exists".
| RUN ln -s /app /app/node_modules/openclaw | |
| RUN ln -sf /app /app/node_modules/openclaw |
Prompt To Fix With AI
This is a comment left during a code review.
Path: Dockerfile
Line: 117
Comment:
**Use `ln -sf` for consistency and idempotency**
The rest of the Dockerfile uses `ln -sf` (line 242: `ln -sf /app/openclaw.mjs /usr/local/bin/openclaw`), but this line uses plain `ln -s`. While `pnpm prune --prod` currently removes the self-referencing symlink, using `-f` (force) would make this layer idempotent and guard against future `pnpm` version changes that might leave the symlink in place — causing the build to fail with "File exists".
```suggestion
RUN ln -sf /app /app/node_modules/openclaw
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5989881c2f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // Plugin runtime module — the lazy resolver walks up from import.meta.url | ||
| // looking for runtime/index.{ts,js}. In production Docker builds /app/src/ | ||
| // is absent, so this must be compiled into dist/runtime/index.js. | ||
| entry: { "runtime/index": "src/plugins/runtime/index.ts" }, |
There was a problem hiding this comment.
Emit plugin runtime at path loader resolves
This entry builds src/plugins/runtime/index.ts into dist/runtime/index.js, but the runtime resolver only checks src/plugins/runtime/index.ts and dist/plugins/runtime/index.js (src/plugins/loader.ts, resolvePluginRuntimeModulePath, candidates at lines 211-218). In production Docker images where /app/src is absent, that mismatch means the new artifact is never discovered and startup can still fail with Unable to resolve plugin runtime module.
Useful? React with 👍 / 👎.
b071e9e to
90f0ebc
Compare
|
Similar PRs and issues #48422 — duplicate/adjacent runtime-module breakage you referenced #48447 — fix: mirror bundled extension deps in root package.json (#48189) Root-cause / enabling PRs #45725 — refactor: move WhatsApp channel implementation to extensions/ #45967 — refactor: remove channel shim directories, point all imports to extensions #32223 — container builds: opt-in extension deps via OPENCLAW_EXTENSIONS build arg Same symptom family: packaged/runtime module resolution breaks #46609 — Signal plugin failed to load: Cannot find module '../../../src/infra/outbound/send-deps.js' #47021 — Telegram plugin fails after refactor: Cannot find module '../../../src/infra/outbound/deliver.js' #41832 — BlueBubbles plugin fails to load: Cannot find module '../../../src/infra/parse-finite-number.js' #32662 — Nextcloud Talk failed to load: Cannot find module '../../../src/infra/abort-signal.js' #37915 — Nextcloud Talk plugin fails to load: same abort-signal.js packaging failure #18846 — llm-task dynamic import fails for pi-embedded-runner.js because source/dist agent entry is missing |
90f0ebc to
e849524
Compare
|
Closing this as implemented after Codex review. Current main already covers the reported Docker self-build/runtime failure through later plugin runtime-deps and plugin-sdk alias fixes, so this PR's Dockerfile-only workaround is obsolete on main. What I checked:
So I’m closing this as already implemented rather than keeping a duplicate issue open. Review notes: reviewed against 4013c658537e; fix evidence: commit 48b9452c0795. |
docker: fix self-build breakage after extension migration
Summary
Fix two Docker self-build issues that prevent the gateway from starting
after the channel-to-extension migration (
16505718e8,439c21e078).These affect anyone building from the stock
Dockerfileon currentmainand will affect the next tagged release (v2026.3.14+).
The official GHCR image for v2026.3.13 is not affected because channels
had not yet been moved to
extensions/at that point.Problem
After the channel migration to
extensions/, bundled extensions now containhundreds of relative
../../../src/imports that the tsdown bundler resolvesat build time. Two issues in the Docker build pipeline prevent this from
working for self-builders:
OPENCLAW_EXTENSIONSdefaults to empty — the ext-deps stage produceszero
package.jsonfiles, so extension npm deps are never installed.tsdown silently produces zero extension output. The gateway falls back to
Jiti transpilation, which fails because
/app/src/is excluded from theruntime image.
pnpm prune --prodremoves the self-referencingnode_modules/openclawsymlink — plugins import from
openclaw/plugin-sdk/*which requiresthis link to resolve in the pruned runtime image.
Changes (Dockerfile only)
1) Default
OPENCLAW_EXTENSIONSto all bundled extensionsUpdate the ext-deps RUN block so that when
OPENCLAW_EXTENSIONSis emptyor
"__all__", package manifests are copied for every bundled extension.Otherwise, preserve the existing explicit subset behavior.
The empty-string check is critical:
docker-setup.shalways passes--build-arg "OPENCLAW_EXTENSIONS=${OPENCLAW_EXTENSIONS}". When the hostenv var is unset, this sends an empty string — overriding the Dockerfile
ARG default. Treating empty as "all" ensures both
docker build .anddocker-setup.shproduce working builds.2) Restore self-referencing package link after prune
Added in the
runtime-assetsstage afterpnpm prune --prod.Root cause commits
16505718e8extensions/(#45725)../../../src/imports439c21e078extensions/57f19f0d5cOPENCLAW_EXTENSIONSbuild arg (#32223)b46ac250d1node_modules/openclawsymlink essentiale9cf3506fdVerification
Backward compatibility
OPENCLAW_EXTENSIONS(including the implicit empty string fromdocker-setup.shwhen the env var is unset) now builds all extensionsinstead of building none. This is the key behavior change — it turns a
broken default into a working one.
OPENCLAW_EXTENSIONS="__all__"is accepted as an explicit alias forthe same behavior.
OPENCLAW_EXTENSIONS="whatsapp telegram"(etc.) continues to workas before — only the listed extensions have their npm deps installed
at build time. tsdown still compiles all extensions found via
openclaw.plugin.json; extensions whose third-party deps are missingemit unresolved-import warnings but produce working output for any
imports resolved from the root package deps.
ln -sis POSIX standard, compatible with all Docker base images.Testing
docker buildwith no--build-argproduces working image with all extensionsdocker build --build-arg OPENCLAW_EXTENSIONS="whatsapp device-pair"builds with subset depsdocker-setup.shwith unsetOPENCLAW_EXTENSIONSenv var builds all extensionspnpm exec vitest run --config vitest.gateway.config.tspassesRelated
mainbroken — gateway fails to start after channel-to-extension migration #48552