# NousResearch/hermes-agent · Moonshot schema crashes on JSON Schema union types

## Open now

- 0 issues, 2 PRs open on GitHub.
- PR #28322: fix: handle Moonshot union type lists
- PR #32516: fix(parser): handle list-form response field for kimi-k2 cloud (#28787)

Multiple bug reports and fix attempts addressing a TypeError caused by unhashable list values when Moonshot/Kimi tool schema sanitization encounters JSON Schema union type arrays. The fixes target two crash sites: _fill_missing_type and sanitize_moonshot_tools.

## TL;DR

- 12 member(s): 0 open issue(s), 3 closed issue(s), 2 open PR(s), 1 merged PR(s), 6 PR(s) closed without merging.
- A fix was merged to main in PR #45579. Verify it addresses your case.
- **Recommended:** read PR #45579 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `partially_resolved` · deciding PR(s): `pr-45579`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
- Members outside that structural core may belong to a different underlying problem.
- Pairwise link density `0.17`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #28291: Bug: moonshot_schema._fill_missing_type crashes on JSON Schema union types (list type)
- #28787: TypeError: unhashable type: 'list' on kimi-k2.6:cloud via Ollama AND direct cloud — response parsing bug
- #30095: kimi-k2.6: TypeError: unhashable type 'list' in sanitize_moonshot_tools when tool has union type parameter

## Prior & competing PRs

- **#28422: fix: handle JSON Schema union type lists in moonshot_schema (both crash sites)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `5acd185f7ced2c629f5c36387f01c4ceb5fb4c9b`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#28772: fix(agent): accept union types in Moonshot schema sanitizer**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `5acd185f7ced2c629f5c36387f01c4ceb5fb4c9b`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#29228: fix(moonshot): handle JSON Schema union types in _fill_missing_type (#28291)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#28422`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#30753: fix(moonshot): normalise union type arrays in _fill_missing_type to prevent TypeError**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `5acd185f7ced2c629f5c36387f01c4ceb5fb4c9b`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#45579: fix(moonshot): handle union type arrays in tool schemas**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `agent/moonshot_schema.py`, `tests/agent/test_moonshot_schema.py`
  - fix hunks:
  - `agent/moonshot_schema.py`

    ```diff
    @@ -135,7 +135,14 @@ def _repair_schema(node: Any, is_schema: bool = True) -> Any:
     
     def _fill_missing_type(node: Dict[str, Any]) -> Dict[str, Any]:
         """Infer a reasonable ``type`` if this schema node has none."""
    -    if "type" in node and node["type"] not in {None, ""}:
    +    node_type = node.get("type")
    +    if isinstance(node_type, list):
    +        concrete = next(
    +            (t for t in node_type if isinstance(t, str) and t not in {"", "null"}),
    +            "string",
    +        )
    +        return {**node, "type": concrete}
    +    if "type" in node and node_type not in {None, ""}:
             return node
     
         # Heuristic: presence of ``properties`` → object, ``items`` → array, ``enum``
    ```
  - `tests/agent/test_moonshot_schema.py`

    ```diff
    @@ -397,3 +397,52 @@ def test_anyof_collapse_still_runs_nullable_and_enum_cleanup(self):
             assert db_type["type"] == "string"
             assert db_type["enum"] == ["mysql", "postgresql"], \
                 "null/empty enum values must be stripped after anyOf collapse"
    +
    +
    +class TestUnionTypeList:
    +    """Moonshot sanitizer accepts JSON Schema union type arrays."""
    +
    +    def test_union_type_list_normalizes_to_first_concrete_type(self):
    +        params = {
    +            "type": "object",
    +            "properties": {
    +                "limit": {
    +                    "type": ["number", "string"],
    +                    "description": "Max results",
    +                },
    +            },
    +        }
    +
    +        out = sanitize_moonshot_tool_parameters(params)
    +
    +        assert out["properties"]["limit"]["type"] == "number"
    +
    +    def test_union_type_list_skips_null_type(self):
    +        params = {
    +            "type": "object",
    +            "properties": {
    +                "name": {"type": ["null", "string"]},
    +            },
    +        }
    +
    +        out = sanitize_moonshot_tool_parameters(params)
    +
    +        assert out["properties"]["name"]["type"] == "string"
    +
    +    def test_union_type_list_with_enum_does_not_crash_or_mutate_input(self):
    +        params = {
    +            "type": "object",
    +            "properties": {
    +                "sort": {
    +                    "type": ["string", "null"],
    +                    "enum": ["asc", "desc", None, ""],
    +                },
    +            },
    +        }
    +
    +        out = sanitize_moonshot_tool_parameters(params)
    +
    +        sort = out["properties"]["sort"]
    +        assert sort["type"] == "string"
    +        assert sort["enum"] == ["asc", "desc"]
    +        assert params["properties"]["sort"]["type"] == ["string", "null"]
    ```
- **#28322: fix: handle Moonshot union type lists**. open
  - maintainer direction: category `uncategorized`; implication `needs_llm`; refs `5acd185f7ced2c629f5c36387f01c4ceb5fb4c9b`
  - files: `agent/moonshot_schema.py`, `tests/agent/test_moonshot_schema.py`
- **#28879: fix(moonshot): flatten union types before set check to avoid TypeError (#28787, #28291)**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#28422`, `#28772`, `#28322`
- **#30226: fix(moonshot): handle union type arrays in sanitize_moonshot_tools (#30095)**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `5acd185f7`, `#45579`
- **#32516: fix(parser): handle list-form response field for kimi-k2 cloud (#28787)**. open
  - maintainer direction: category `uncategorized`; implication `needs_llm`; refs `5acd185f7ced`, `#28787`
  - files: `agent/agent_runtime_helpers.py`, `agent/chat_completion_helpers.py`, `tests/cli/test_reasoning_command.py`

## Fix status

- Merged to main in PR #45579 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-06-13`.
- Subsystem: `agent`
