Skip to content

Slack Socket Mode crashes on boot with invalid_auth — appToken missing from baked openclaw.json; placeholder resolution also broken #2085

@nimeshkummar

Description

@nimeshkummar

[bug] Slack Socket Mode crashes on boot with invalid_authappToken missing from baked openclaw.json; token resolution also appears broken

Summary

NemoClaw v0.0.20 onboarding with the Slack messaging channel selected produces a
sandbox that cannot connect to Slack. On every boot the gateway crashes with
an unhandled promise rejection:

[openclaw] Unhandled promise rejection: Error: An API error occurred: invalid_auth
    at platformErrorFromResult (.../@slack/web-api/src/errors.ts:119:5)
    at WebClient.apiCall (.../@slack/web-api/src/WebClient.ts:405:36)

The crash takes the entire gateway down (and with it, the dashboard at
:18789), so the sandbox is unusable whenever Slack credentials are present.

Environment

  • NemoClaw: v0.0.20
  • Host: macOS 26.3.1 on Apple M4 Mac Mini (16 GB unified memory)
  • Runtime: Docker Desktop
  • Inference provider: ollama-local / gemma4:e4b
  • Messaging channel: slack (Socket Mode)
  • Policy tier: Balanced + slack preset applied
  • Install path: interactive nemoclaw onboard, with later
    nemoclaw nemo rebuild and nemoclaw onboard --non-interactive --resume --recreate-sandbox iterations while debugging.

Two issues that together cause the crash

Issue 1 — generated openclaw.json is missing appToken

The Dockerfile generates the baked openclaw.json from
NEMOCLAW_MESSAGING_CHANNELS_B64. The Python block at Dockerfile:245:

_token_keys = {'discord': 'token', 'telegram': 'botToken', 'slack': 'botToken'}
_env_keys   = {'discord': 'DISCORD_BOT_TOKEN',
               'telegram': 'TELEGRAM_BOT_TOKEN',
               'slack':    'SLACK_BOT_TOKEN'}
_ch_cfg = {ch: {'accounts': {'default': {
    _token_keys[ch]: f'openshell:resolve:env:{_env_keys[ch]}',
    'enabled': True, ...
}}} for ch in msg_channels if ch in _token_keys}

Result: the baked /sandbox/.openclaw/openclaw.json has only botToken for
Slack. No appToken. @slack/bolt Socket Mode cannot initialize without an
App-Level Token, so apps.connections.open fails immediately.

Observed baked config:

"channels": {
  "slack": {
    "accounts": {
      "default": {
        "botToken": "openshell:resolve:env:SLACK_BOT_TOKEN",
        "enabled": true
        // NOTE: appToken is missing
      }
    }
  }
}

Issue 2 — openshell:resolve:env:* placeholders never resolve to real tokens

Even after patching the Dockerfile to also emit
"appToken": "openshell:resolve:env:SLACK_APP_TOKEN", the Slack SDK still
receives invalid_auth.

Inside the sandbox:

$ env | grep SLACK
SLACK_BOT_TOKEN=openshell:resolve:env:SLACK_BOT_TOKEN
SLACK_APP_TOKEN=openshell:resolve:env:SLACK_APP_TOKEN

i.e. the literal marker strings, not the real tokens. For Brave, the same
marker appears in openclaw.json but the sandbox env has the real value
(because openshell sandbox create is called with
--env BRAVE_API_KEY=BSA... directly). For Slack there is no equivalent — the
openshell sandbox create command records:

--provider nemo-slack-bridge --provider nemo-slack-app -- env CHAT_UI_URL=... BRAVE_API_KEY=BSA...

No SLACK_BOT_TOKEN=... or SLACK_APP_TOKEN=... injected. The
nemo-slack-bridge and nemo-slack-app OpenShell providers are registered
with credential keys, but setting them via:

openshell provider update nemo-slack-bridge --credential SLACK_BOT_TOKEN=xoxb-...
openshell provider update nemo-slack-app    --credential SLACK_APP_TOKEN=xapp-...

does not cause the L7 proxy to substitute the placeholder strings. Requests
reach slack.com with Authorization: Bearer openshell:resolve:env:SLACK_BOT_TOKEN
(inferred from the invalid_auth response; the real tokens are verified valid
via curl from the host).

Gateway container env is also empty of slack tokens:

$ docker exec openshell-cluster-nemoclaw env | grep -i slack
# (no output)

So neither the sandbox env, nor the proxy container env, nor the openclaw.json
itself contains the real token values, despite nemoclaw credentials list
showing both tokens stored.

Reproduction

  1. Fresh install: curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash
  2. Onboarding: nemoclaw onboard
    • Inference: Install Ollama / gemma4:e4b
    • Messaging: Slack only, paste valid xoxb- and xapp- tokens
    • Policy tier: Balanced; verify slack preset is toggled on
  3. Wait for the sandbox to come up.
  4. Observe (inside sandbox):
    cat /sandbox/.openclaw/openclaw.json | jq '.channels.slack'
    # → only botToken, no appToken
    env | grep SLACK
    # → openshell:resolve:env:... literals, not real tokens
    
  5. Tail the sandbox gateway log — crash loop on invalid_auth within seconds of
    [slack] [default] starting provider.

Expected behavior

  • openclaw.json includes appToken when Slack is selected, so Socket Mode
    has what it needs.
  • openshell:resolve:env:* placeholders are resolved (either at build time
    when tokens are baked, at sandbox-create env injection time like Brave, or
    at egress-proxy rewrite time) so that Authorization: Bearer <real-token>
    reaches Slack.
  • Dashboard stays up on boot regardless of whether Slack auth succeeds
    (a single channel failure should not crash the entire gateway — the
    unhandled promise rejection should be caught and the channel marked
    unavailable in the UI).

Local patch I applied (partial fix)

Edited Dockerfile line 247 to append an appToken spread for slack:

- **({'dmPolicy': ...} if ... else {})}}}
+ **({'dmPolicy': ...} if ... else {}), **({'appToken': 'openshell:resolve:env:SLACK_APP_TOKEN'} if ch == 'slack' else {})}}}

After rebuild, openclaw.json contains both botToken and appToken, but
the runtime invalid_auth persists because Issue 2 is unresolved — the proxy
or sandbox env never receives the real token values.

Additional notes / related papercuts surfaced while debugging

  1. Race condition on sandbox boot. Policy presets are applied AFTER
    openshell sandbox create, so on first boot the sandbox egress denies
    slack.com:443 and the gateway crashes with Failed to establish tunnel to slack.com:443 ... HTTP/1.1 403 Forbidden. By the time the slack preset
    lands, the process has exited. A subsequent manual restart of the gateway
    does reach Slack, but only to hit Issue 2.

  2. Rebuild refuses when sandbox is already dead. nemoclaw nemo rebuild
    exits with "Sandbox 'nemo' is not running. Cannot back up state. Start it
    first or recreate with nemoclaw onboard --recreate-sandbox." This is
    accurate messaging but traps users whose sandbox crashed on the Slack bug
    above — they now need the slower onboard-recreate path to recover.

  3. credentials list has no add counterpart. Once a credential is
    missing, the only documented way to re-enter it is to re-run
    nemoclaw onboard, which forces another rebuild. A nemoclaw credentials set KEY (reading from stdin silently) would help a lot — especially since
    the current onboarding flow re-pulls the Docker validation image and risks
    the macOS keychain lock issue ([WSL2] NemoClaw sandbox cannot reach Windows-hosted Ollama — local inference path blocked (relates to #305, #315, #246) #336 is adjacent) over SSH sessions.

  4. Dashboard exits with gateway crash. Because the dashboard is served by
    the same node process as the Slack provider, one unhandled promise
    rejection takes the whole UI down. Users then can't even see the failure
    state in the dashboard — the port is unresponsive.

Happy to contribute a PR for Issue 1 (the Dockerfile appToken fix is a
one-liner). Issue 2 likely needs someone with visibility into the
openshell:resolve:env:* resolution path to point me at the right surface.

References

Metadata

Metadata

Assignees

Labels

integration: slackSlack integration or channel behavior

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions