Skip to content

[Bug]: Null Values in SessionResetPolicy Configuration Cause TypeError #1119

@chrisqianz

Description

@chrisqianz

Bug Description

When users explicitly set at_hour or idle_minutes to null in their config.yaml, the SessionResetPolicy.from_dict() method fails to apply default values, resulting in None being passed to validation logic. This causes a TypeError when comparing None with integers.

The issue stems from Python's dict.get() behavior: it only returns the default value when a key is missing, not when the key exists but has a null value.

Steps to Reproduce

  1. Open your ~/.hermes/config.yaml file
  2. Modify the default_reset_policy section to include explicit null values:
default_reset_policy:
  mode: both
  at_hour: null
  idle_minutes: null
  1. Restart the Hermes Gateway:

    hermes gateway restart
    # OR
    launchctl stop ai.hermes.gateway && launchctl load ~/Library/LaunchAgents/ai.hermes.gateway.plist
  2. Check the gateway logs:

    tail -f ~/.hermes/logs/gateway.log

Expected Behavior

The gateway should:

  • Accept null values in the configuration
  • Apply default values (at_hour: 4, idle_minutes: 1440) when null is specified
  • Start successfully without errors
  • Use the default reset policy values

Actual Behavior

The gateway:

  • Accepts null values but does not apply defaults
  • Sets policy.at_hour and policy.idle_minutes to None
  • Fails during validation with TypeError when checking 0 <= policy.at_hour <= 23
  • May crash or behave unpredictably
  • Logs errors in the gateway log file

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

Messaging Platform (if gateway-related)

Telegram

Operating System

macOS 14.5

Python Version

3.11.13

Hermes Version

0.20

Relevant Logs / Traceback

Traceback (most recent call last):
  File "/Users/chrisqian/Development/hermes-agent/.venv/bin/hermes", line 10, in <module>
    sys.exit(main())
             ^^^^^^
  File "/Users/chrisqian/Development/hermes-agent/hermes_cli/main.py", line 2647, in main
    args.func(args)
  File "/Users/chrisqian/Development/hermes-agent/hermes_cli/main.py", line 508, in cmd_gateway
    gateway_command(args)
  File "/Users/chrisqian/Development/hermes-agent/hermes_cli/gateway.py", line 960, in gateway_command
    run_gateway(verbose, replace=replace)
  File "/Users/chrisqian/Development/hermes-agent/hermes_cli/gateway.py", line 417, in run_gateway
    success = asyncio.run(start_gateway(replace=replace))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chrisqian/Library/Application Support/uv/python/cpython-3.11.13-macos-x86_64-none/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/Users/chrisqian/Library/Application Support/uv/python/cpython-3.11.13-macos-x86_64-none/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chrisqian/Library/Application Support/uv/python/cpython-3.11.13-macos-x86_64-none/lib/python3.11/asyncio/base_events.py", line 654, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/Users/chrisqian/Development/hermes-agent/gateway/run.py", line 3536, in start_gateway
    runner = GatewayRunner(config)
             ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chrisqian/Development/hermes-agent/gateway/run.py", line 223, in __init__
    self.config = config or load_gateway_config()
                            ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chrisqian/Development/hermes-agent/gateway/config.py", line 316, in load_gateway_config
    if not (0 <= policy.at_hour <= 23):
            ^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: '<=' not supported between instances of 'int' and 'NoneType'

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

Update SessionResetPolicy.from_dict() to explicitly handle null values:

@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "SessionResetPolicy":
    """
    Create SessionResetPolicy from dictionary configuration.
    
    Handles both missing keys and explicit null values correctly.
    """
    # Handle None values explicitly — data.get() returns None if key exists with null value
    at_hour = data.get("at_hour")
    if at_hour is None:
        at_hour = 4
    idle_minutes = data.get("idle_minutes")
    if idle_minutes is None:
        idle_minutes = 1440
    
    return cls(
        mode=data.get("mode", "both"),
        at_hour=at_hour,
        idle_minutes=idle_minutes,
    )

Are you willing to submit a PR for this?

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/bugSomething isn't working

    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