hermes - ✅(Solved) Fix [Bug]: slack adapter silently disabled when config.yaml has top-level slack: block (regression in a01e767b) [1 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#16682Fetched 2026-04-28 06:51:37
View on GitHub
Comments
2
Participants
2
Timeline
13
Reactions
1
Timeline (top)
labeled ×5subscribed ×3commented ×2closed ×1

Error Message

No Python traceback. This is a silent suppression — the only signal is the absence of expected log lines.

Pre-a01e767b (working): INFO gateway.run: Connecting to slack... INFO gateway.platforms.slack: [Slack] Authenticated as @hermes … INFO gateway.run: ✓ slack connected INFO gateway.run: Gateway running with 2 platform(s)

Post-a01e767b with same env + same yaml: INFO gateway.run: Connecting to webhook... INFO gateway.run: ✓ webhook connected INFO gateway.run: Gateway running with 1 platform(s)

Root Cause

The root cause is that the yaml-bridging loop adds Platform.SLACK to config.platforms whenever any bridged key (channel_prompts, require_mention, channel_skill_bindings, etc.) is present in the top-level slack: block. Once it's in config.platforms, the new env-override code path skips the enabled = True branch and the adapter is suppressed — even though the user has done nothing to disable it.

Fix Action

Fixed

PR fix notes

PR #16738: fix(gateway): treat yaml slack block without explicit enabled as opt-in (#16682)

Description (problem / solution / changelog)

What does this PR do?

Commit a01e767b (fix(gateway): respect config.yaml slack.enabled when SLACK_BOT_TOKEN env var is set) introduced a regression: any pre-existing setup with a top-level slack: block in config.yaml — even one with no enabled key — silently fails to start the Slack adapter. The gateway logs running with N platform(s) and Slack isn't in the list, with no warning or error.

The post-a01e767b env-override path uses Platform.SLACK in config.platforms as a proxy for "user explicitly set enabled". That proxy is wrong: the yaml-bridging loop in gateway/config.py adds Platform.SLACK to config.platforms whenever any bridged key is present (channel_prompts, require_mention, channel_skill_bindings, free_response_channels, dm_policy, allow_from, group_policy, …), regardless of whether the user touched the enabled field. Once the platform is in config.platforms with the dataclass default enabled=False, the env-override branch skips the activation step and the adapter is suppressed.

Fix: track whether enabled was actually present in the source dict and gate the env-override on that signal.

Related Issue

Fixes #16682

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • gateway/config.py:PlatformConfig — added a private _enabled_explicit: bool field (excluded from repr / compare, not serialized via to_dict). from_dict sets it iff the source dict actually contains an "enabled" key, so dataclass-default platforms are distinguishable from yaml-explicit ones at env-override time.

  • gateway/config.py:_apply_env_overrides — Slack env-token branch now distinguishes three cases:

    1. Platform.SLACK not in config.platforms → create with enabled=True (env-only setup, unchanged behavior).
    2. Platform.SLACK present but _enabled_explicit=False → set enabled=True (yaml has bridged keys but never touched enabled — restores pre-a01e767b behavior).
    3. Platform.SLACK present with _enabled_explicit=True → respect whatever the yaml said (preserves the a01e767b fix for users who explicitly set enabled: false).

    In every case the env token is still stored on the PlatformConfig, so skills that send Slack messages can use it without activating the gateway adapter.

  • tests/gateway/test_config.py — new TestSlackEnvTokenActivation covering the four shapes:

    1. yaml has bridged keys without enabled + env token → enabled (the actual #16682 repro case)
    2. yaml has explicit enabled: false + env token → adapter disabled, token stored
    3. env-only setup (no yaml block) → enabled
    4. yaml has explicit enabled: true + env token → enabled

    Of these four, only case 1 fails on current main and passes after this fix; the other three exercise behavior the original a01e767b fix intentionally introduced and that this PR preserves.

How to Test

Reproduction (matches the issue body):

  1. Set SLACK_BOT_TOKEN and SLACK_APP_TOKEN in ~/.hermes/.env.
  2. In ~/.hermes/config.yaml, add (only):
    slack:
      channel_prompts: {}
  3. Restart the gateway: hermes gateway restart (or systemctl --user restart hermes-gateway.service).
  4. Before this fix: gateway log shows running with N platform(s) without Slack listed.
  5. After this fix: Slack appears in the platform list and connects normally.

Automated:

pytest tests/gateway/test_config.py -q

Result on macOS 15.6.1 / Python 3.14.2: 37 passed.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15.6.1 (Python 3.14.2)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A (field has an inline docstring on PlatformConfig explaining when it's used)
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A (N/A — no new config keys; restores prior behavior for an existing one)
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A (N/A)
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A (N/A — pure dataclass / dict logic)
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A (N/A — gateway config, not a tool)

Screenshots / Logs

$ pytest tests/gateway/test_config.py -q
.....................................                                    [100%]
37 passed, 37 warnings in 3.38s

Changed files

  • gateway/config.py (modified, +27/-12)
  • tests/gateway/test_config.py (modified, +88/-0)

Code Example

slack:
    channel_prompts: {}

---

platforms:
    slack:
      enabled: true

---

N/A - Debug logs won't diagnose this.

---

No Python traceback. This is a silent suppression — the only signal is the absence of expected log lines.

  Pre-a01e767b (working):
  INFO gateway.run: Connecting to slack...
  INFO gateway.platforms.slack: [Slack] Authenticated as @hermes …
  INFO gateway.run: ✓ slack connected
  INFO gateway.run: Gateway running with 2 platform(s)

  Post-a01e767b with same env + same yaml:
  INFO gateway.run: Connecting to webhook...
  INFO gateway.run: ✓ webhook connected
  INFO gateway.run: Gateway running with 1 platform(s)

---

slack_token = os.getenv("SLACK_BOT_TOKEN")
  if slack_token:
      if Platform.SLACK not in config.platforms:
          # No yaml config for Slack — env-only setup, enable it
          config.platforms[Platform.SLACK] = PlatformConfig()
          config.platforms[Platform.SLACK].enabled = True
      # If yaml config exists, respect its enabled flag …
      config.platforms[Platform.SLACK].token = slack_token
RAW_BUFFERClick to expand / collapse

Bug Description

After commit a01e767b (fix(gateway): respect config.yaml slack.enabled when SLACK_BOT_TOKEN env var is set), the Slack gateway adapter silently fails to start whenever config.yaml contains a top-level slack: block — even if that block has no enabled key. Setting SLACK_BOT_TOKEN no longer enables the adapter the way it did pre-commit; the gateway just logs Gateway running with N platform(s) and Slack isn't in the list. No warning, no error.

The root cause is that the yaml-bridging loop adds Platform.SLACK to config.platforms whenever any bridged key (channel_prompts, require_mention, channel_skill_bindings, etc.) is present in the top-level slack: block. Once it's in config.platforms, the new env-override code path skips the enabled = True branch and the adapter is suppressed — even though the user has done nothing to disable it.

This produces a silent, hard-to-diagnose breakage for any pre-existing setup that had a slack: block (which is the natural place users put channel_prompts, etc.) and relied on SLACK_BOT_TOKEN to enable the adapter. In a multi-profile deployment it can take down Slack across every profile at once.

Steps to Reproduce

  1. Have a working Slack gateway prior to a01e767b, with SLACK_BOT_TOKEN and SLACK_APP_TOKEN in the environment and a ~/.hermes/config.yaml like:
  slack:
    channel_prompts: {}
  1. Pull a01e767b (or any release that includes it).
  2. Restart the gateway: systemctl --user restart hermes-gateway.service.
  3. Tail ~/.hermes/logs/gateway.log and observe:
    • Connecting to webhook...
    • Gateway running with 1 platform(s)
    • No Connecting to slack... line, no warning, no error.
  4. In Slack, send the bot a DM. It does not respond.
  5. Confirm the tokens are still valid by inspecting /proc/<gateway-pid>/environ (SLACK_BOT_TOKEN/SLACK_APP_TOKEN are present).

Expected Behavior

Either of:

  • SLACK_BOT_TOKEN set → adapter enabled, unless config.yaml explicitly sets enabled: false. (Pre-a01e767b behavior.)
  • Or, if the new behavior is intentional, the gateway should log a clear warning when a token is set but the adapter is suppressed — e.g.: Slack token set but adapter not started — add 'platforms.slack.enabled: true' to config.yaml.

Actual Behavior

Adapter is silently skipped. There is no log line indicating Slack was even considered. The user only finds out when the bot stops answering in Slack, and the only way to diagnose is to read gateway/config.py and trace the env-override code path.

The needed fix is non-obvious: adding enabled: true to the existing top-level slack: block does not work, because enabled is not in the bridged-keys list at gateway/config.py:580-624. Users have to add a separate top-level platforms: block:

  platforms:
    slack:
      enabled: true

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

Messaging Platform (if gateway-related)

Slack

Debug Report

N/A - Debug logs won't diagnose this.

Operating System

Ubuntu 24.04.4 LTS (Noble Numbat)

Python Version

3.11.15

Hermes Version

0.11.0

Additional Logs / Traceback (optional)

No Python traceback. This is a silent suppression — the only signal is the absence of expected log lines.

  Pre-a01e767b (working):
  INFO gateway.run: Connecting to slack...
  INFO gateway.platforms.slack: [Slack] Authenticated as @hermes …
  INFO gateway.run: ✓ slack connected
  INFO gateway.run: Gateway running with 2 platform(s)

  Post-a01e767b with same env + same yaml:
  INFO gateway.run: Connecting to webhook...
  INFO gateway.run: ✓ webhook connected
  INFO gateway.run: Gateway running with 1 platform(s)

Root Cause Analysis (optional)

Two interacting code paths in gateway/config.py:

  1. The yaml-bridging loop at lines 574-624 walks each Platform and, when a top-level slack: block contains any bridged key (channel_prompts, require_mention,channel_skill_bindings, mention_patterns, etc.), inserts Platform.SLACK into platforms_data with an extra dict. enabled is not in the bridged-keys set, so the resulting PlatformConfig has enabled=False (the dataclass default).

  2. The env-override code at lines 938-947 (introduced/changed by a01e767b):

slack_token = os.getenv("SLACK_BOT_TOKEN")
  if slack_token:
      if Platform.SLACK not in config.platforms:
          # No yaml config for Slack — env-only setup, enable it
          config.platforms[Platform.SLACK] = PlatformConfig()
          config.platforms[Platform.SLACK].enabled = True
      # If yaml config exists, respect its enabled flag …
      config.platforms[Platform.SLACK].token = slack_token
  1. Because step (1) put Platform.SLACK into config.platforms, the enabled = True branch is skipped. The token is stored but the adapter is never activated.

The original commit's intent was to support skills-only SLACK_BOT_TOKEN usage (e.g., cron jobs that send Slack messages without running the gateway adapter). It conflated "yaml mentions Slack at all" with "yaml says enabled: false", which is what causes the regression.

Proposed Fix (optional)

Any of these would resolve it; combining (1) and (3) gives the best UX:

  1. Treat enabled as tri-state. Distinguish "yaml didn't mention enabled" from "yaml said enabled: false". Only the latter should suppress activation when SLACK_BOT_TOKEN is set. The skills-only use case the original commit cared about can be expressed by an explicit enabled: false (or, more cleanly, by checking that SLACK_APP_TOKEN is also present before activating the adapter — its absence is what produced the original SLACK_APP_TOKEN not set errors).
  2. Bridge enabled from the top-level slack: block. Add enabled to the bridged-keys set in the yaml loop (lines 580-624). That would let users put enabled: true next to channel_prompts — which is the natural location and matches what migration-on-upgrade users expect.
  3. Log a warning when a token is set but the adapter is suppressed. Even keeping current behavior, a single logger.warning(...) line pointing at platforms.slack.enabled: true would have saved hours of diagnosis. Apply the same pattern to Discord/Telegram if they share the structure.

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

extent analysis

TL;DR

To fix the silent failure of the Slack gateway adapter, add a separate top-level platforms block to your config.yaml with slack enabled.

Guidance

  • The issue arises from the interaction between the yaml-bridging loop and the env-override code path in gateway/config.py, causing the adapter to be suppressed even when SLACK_BOT_TOKEN is set.
  • To resolve this, add the following to your config.yaml:
platforms:
  slack:
    enabled: true
  • This will ensure the Slack adapter is enabled even when SLACK_BOT_TOKEN is set and there's a top-level slack block in the config.
  • Alternatively, treating enabled as tri-state or bridging enabled from the top-level slack block could also resolve the issue, but these require code changes.

Example

No code changes are necessary for the immediate workaround; simply update your config.yaml as shown above.

Notes

The proposed fixes involve either changing the gateway/config.py to treat enabled as tri-state, bridging enabled from the top-level slack block, or logging a warning when the adapter is suppressed. However, the simplest and most immediate solution is to update the config.yaml as described.

Recommendation

Apply the workaround by adding the platforms block to your config.yaml, as this is the most straightforward and immediate solution to the problem.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Bug]: slack adapter silently disabled when config.yaml has top-level slack: block (regression in a01e767b) [1 pull requests, 2 comments, 2 participants]