Skip to content

[Bug]: Docker self-build from main broken — gateway fails to start after channel-to-extension migration #48552

@gbballpack

Description

@gbballpack

[Bug]: Docker self-build from main broken — gateway fails to start after channel-to-extension migration

Summary

Building the Docker image from the stock Dockerfile on current main produces a gateway that fails to start. The process launches but errors out during channel and plugin loading before ever reaching a listening state. Two issues in the Dockerfile interact to cause this.

This affects every self-builder using Docker — anyone who runs docker build -f Dockerfile . or uses docker-setup.sh on current main. The next tagged release (v2026.3.14+) will carry these issues unless fixed.

The official GHCR image for v2026.3.13 is not affected because the channel-to-extension migration had not yet landed at that tag.

Symptoms

Depending on which issue hits first, the gateway logs one or more of:

[plugins] whatsapp failed to load from /app/extensions/whatsapp/index.ts:
Error: Cannot find module '../../../src/channels/plugins/account-helpers.js'
Cannot find package 'openclaw' imported from /app/dist/...

(A third symptom — Error: Unable to resolve plugin runtime module — was independently fixed on main via the buildUnifiedDistEntries() refactor that added "plugins/runtime/index" to buildCoreDistEntries(). See #48422.)

Root cause

The channel-to-extension migration (PRs #45725, #45967) moved all channels into extensions/. These extensions now contain hundreds of relative ../../../src/ imports that the tsdown bundler resolves at build time. Two issues in the Dockerfile prevent this from working:

1. OPENCLAW_EXTENSIONS defaults to empty — extensions don't get compiled

Commit Description
16505718e8 Move WhatsApp to extensions/ (#45725)
439c21e078 Remove channel shim dirs, point imports to extensions (#45967)
57f19f0d5c Add OPENCLAW_EXTENSIONS build arg (#32223)

The Dockerfile ARG OPENCLAW_EXTENSIONS="" means the ext-deps stage copies zero package.json files. Extension npm deps are never installed, so the tsdown bundler silently produces zero dist/extensions/ output. The gateway falls back to Jiti transpilation of raw .ts from extensions/, which fails because /app/src/ is excluded from the runtime image and the extensions use ../../../src/ relative imports.

Compounding this, docker-setup.sh always passes --build-arg "OPENCLAW_EXTENSIONS=${OPENCLAW_EXTENSIONS}". When the host env var is unset, this sends an empty string to the build — overriding whatever the Dockerfile ARG default is. So even changing the default to a non-empty value isn't sufficient; the fix must also treat empty string as "build all."

2. pnpm prune --prod removes the self-referencing symlink

Commit Description
b46ac250d1 WhatsApp: use scoped plugin SDK imports
e9cf3506fd Telegram: use scoped plugin SDK imports

After the v2026.3.7 scoped-import migration, plugins import from openclaw/plugin-sdk/* subpaths which require node_modules/openclaw to resolve. The Dockerfile's pnpm prune --prod step removes this self-referencing link, breaking all SDK subpath imports at runtime.

Reproduction

git clone https://github.com/openclaw/openclaw.git
cd openclaw
docker build -t openclaw:local -f Dockerfile .

# Verify extensions weren't compiled:
docker run --rm openclaw:local sh -c 'ls /app/dist/extensions/ 2>/dev/null | wc -l'
# Expected: 0

# Verify symlink missing:
docker run --rm openclaw:local ls -la /app/node_modules/openclaw 2>/dev/null
# Expected: not found

# Gateway fails to start:
docker run --rm openclaw:local timeout 15 node openclaw.mjs gateway \
  --allow-unconfigured 2>&1 | grep -iE "error|fail" | head -5

Comparison: official GHCR image vs self-built from main

Check Official (v2026.3.13) Self-built from main
dist/extensions/ Does not exist Does not exist (without OPENCLAW_EXTENSIONS)
node_modules/openclaw Does not exist Does not exist
/app/src/ Does not exist Does not exist
extensions/whatsapp/src/accounts.ts Does not exist Exists (new on main)
Gateway starts Yes (Jiti + self-ref exports) No (relative imports fail)

The official image works because extensions/whatsapp/src/accounts.ts doesn't exist in v2026.3.13 — the file was added on main by commit 16505718e8 with relative ../../../src/ imports. Hundreds of similar imports exist across all extensions post-migration.

Fix

PR #48523 addresses both issues (Dockerfile only):

  1. Auto-detect extensions — Default OPENCLAW_EXTENSIONS to "__all__" and treat empty string the same way, so both docker build . and docker-setup.sh produce working builds.
  2. Restore symlink — Add RUN ln -s /app /app/node_modules/openclaw after pnpm prune --prod.

Related

Environment

  • OpenClaw: main (post v2026.3.13, pre v2026.3.14)
  • Node: 24
  • Docker: building from stock Dockerfile
  • OS: Ubuntu 24.04 (VPS)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions