hermes - 💡(How to fix) Fix kimi-k2.6: TypeError: unhashable type 'list' in sanitize_moonshot_tools when tool has union type parameter

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…

Error Message

TypeError: unhashable type: 'list'

Root Cause

_fill_missing_type() in agent/moonshot_schema.py line ~169:

# BROKEN:
if "type" in node and node["type"] not in {None, ""}:
    return node

When node["type"] is a Python list (e.g. ["number", "string"]), the not in {None, ""} set membership test raises:

TypeError: unhashable type: 'list'

because Python lists are not hashable and cannot be tested for set membership.

Code Example

TypeError: unhashable type: 'list'

---

{
  "time_from": {
    "anyOf": [{"type": "number"}, {"type": "string"}],
    "description": "Unix seconds or ISO 8601"
  },
  "limit": {
    "type": ["number", "string"],
    "description": "Max results"
  }
}

---

# BROKEN:
if "type" in node and node["type"] not in {None, ""}:
    return node

---

TypeError: unhashable type: 'list'

---

def _fill_missing_type(node: Dict[str, Any]) -> Dict[str, Any]:
    """Infer a reasonable ``type`` if this schema node has none.

    Handles JSON Schema union types where ``type`` is a list like
    ``["number", "string"]``.  Moonshot does not accept union type arrays —
    we keep the first concrete (non-null) type and discard the rest.
    """
    node_type = node.get("type")
    # Guard: list types (e.g. ["number", "string"]) are not hashable and
    # cannot be tested with `not in {None, ""}`.  Normalise to the first
    # non-null element so the rest of the pipeline sees a plain string type.
    if isinstance(node_type, list):
        concrete = next((t for t in node_type if t not in (None, "null", "")), "string")
        return {**node, "type": concrete}
    if node_type not in {None, ""}:
        return node
    # ... rest of function unchanged
RAW_BUFFERClick to expand / collapse

Bug Description

When using kimi-k2.6 (or any Moonshot model), any tool whose JSON Schema uses a union type array ("type": ["number", "string"]) causes a crash inside sanitize_moonshot_tools():

TypeError: unhashable type: 'list'

This is a hard crash — the agent cannot call any tool that has a union-typed parameter.

Affected Tool Example

The built-in lcm_grep tool has parameters like:

{
  "time_from": {
    "anyOf": [{"type": "number"}, {"type": "string"}],
    "description": "Unix seconds or ISO 8601"
  },
  "limit": {
    "type": ["number", "string"],
    "description": "Max results"
  }
}

Both forms are valid JSON Schema, but the "type": ["number", "string"] form hits the bug directly.

Root Cause

_fill_missing_type() in agent/moonshot_schema.py line ~169:

# BROKEN:
if "type" in node and node["type"] not in {None, ""}:
    return node

When node["type"] is a Python list (e.g. ["number", "string"]), the not in {None, ""} set membership test raises:

TypeError: unhashable type: 'list'

because Python lists are not hashable and cannot be tested for set membership.

Proposed Fix

Detect list types before the set membership test and normalise to the first concrete (non-null) type:

def _fill_missing_type(node: Dict[str, Any]) -> Dict[str, Any]:
    """Infer a reasonable ``type`` if this schema node has none.

    Handles JSON Schema union types where ``type`` is a list like
    ``["number", "string"]``.  Moonshot does not accept union type arrays —
    we keep the first concrete (non-null) type and discard the rest.
    """
    node_type = node.get("type")
    # Guard: list types (e.g. ["number", "string"]) are not hashable and
    # cannot be tested with `not in {None, ""}`.  Normalise to the first
    # non-null element so the rest of the pipeline sees a plain string type.
    if isinstance(node_type, list):
        concrete = next((t for t in node_type if t not in (None, "null", "")), "string")
        return {**node, "type": concrete}
    if node_type not in {None, ""}:
        return node
    # ... rest of function unchanged

Moonshot rejects union type arrays anyway (it requires a single scalar type), so normalising to the first concrete type is both correct and safe.

Steps to Reproduce

  1. Configure Hermes with kimi-k2.6 as the model (via Ollama Cloud or direct Moonshot API)
  2. Enable any toolset that includes lcm_grep (e.g. hermes-cli)
  3. Send any message that triggers tool use
  4. Observe TypeError: unhashable type: 'list' in the agent loop

Environment

  • Hermes version: 0.14.0
  • Model: kimi-k2.6 (moonshotai/kimi-k2.6)
  • Provider: Ollama Cloud / any provider routing to Moonshot
  • Python: 3.12

Notes

  • The anyOf: [{type: number}, {type: string}] form is handled correctly by the existing anyOf collapse logic — only the type: ["number", "string"] array form hits this bug.
  • The fix is a 3-line guard at the top of _fill_missing_type() with no impact on existing behaviour for string types.

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 - 💡(How to fix) Fix kimi-k2.6: TypeError: unhashable type 'list' in sanitize_moonshot_tools when tool has union type parameter