Skip to content

todo_tool: AttributeError 'str' object has no attribute 'get' when LLM emits todos as JSON string #14185

@JayGwod

Description

@JayGwod

Summary

todo_tool crashes with AttributeError: 'str' object has no attribute 'get' when the LLM emits the todos parameter as a JSON-encoded string instead of the declared array.

Observed rate: occurs intermittently across Claude 4.5 / 4.6 / 4.7 (via CRS proxy, opus variants). The crash is harder to reproduce with GPT-5.x but has been observed after a prior tool-call rejection — the model "self-corrects" by wrapping the list in json.dumps, which then fails schema validation downstream.

Reproduction

  1. Invoke todo with the todos field serialized as a string (any of these observed patterns):
    # Pattern A: double-JSON-encoded
    {"todos": '[{"id":"t1","content":"x","status":"pending"}]'}
    # Pattern B: non-dict item in list
    {"todos": ["not-a-dict"]}
  2. Handler throws in TodoStore._validate() / _dedupe_by_id() during item.get("id").

Root cause

todo_tool(), TodoStore._validate() and _dedupe_by_id() assume the caller obeys the declared schema. There is no defensive parsing / type coercion before dict access.

Community evidence

Proposed fix

Three additive guards (~30 LOC, no behavior change for well-formed input):

  1. todo_tool() entry — if todos is a str, attempt json.loads(); if it is neither list nor None, return a clear error instead of crashing.
  2. TodoStore._validate() — coerce non-dict items to a placeholder error record instead of calling .get() on them.
  3. TodoStore._dedupe_by_id() — defensive isinstance check before key access.

All three guards fail closed (return structured error, never raise).

PR

I will open a PR from JayGwod/hermes-agent:fix/todo-tool-type-coercion right after this issue so they can be linked.

Tested locally (both unit tests and live dispatch through the gateway at PID 2473729) — see PR for details.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — major feature broken, no workaroundcomp/toolsTool registry, model_tools, toolsetstype/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