Skip to content

todo_write raw-argument rejections surface no correction hint, causing repeated failed calls #3916

Description

@probepark

Summary

todo_write registers validateRawTodoArguments as its rawArgumentValidation hook, but every rejection returns { outcome: "reject" } without a correction code. validateToolArguments (packages/ai/src/utils/validation.ts) then throws the generic:

Validation failed for tool "todo_write": raw arguments rejected before coercion

No offending key, op, or expected shape is named, so the model has no way to self-correct and repeats the same failed call. Observed in a live session: four consecutive failed todo_write calls across turns, each with the identical opaque message.

Reproduction

All of these are rejected with the same uninformative message:

{"ops":[{"op":"note","note":"..."}]}

(unsupported note key — correct key is text, and note requires task)

{"ops":[{"op":"done","items":["some task"]}]}

(items is accepted by the key allowlist but done/drop require task or phase; items is append-only)

By contrast, an invalid op name reaches Zod validation and produces an actionable message:

- ops/0/op: Invalid option: expected one of "init"|"start"|"done"|"rm"|"drop"|"append"|"note"

So the pre-coercion hook is strictly less helpful than the schema layer it front-runs. Notably, TodoWriteTool.execute already handles the missing done/drop target case with a friendly Missing task or phase for done operation summary — the raw hook rejects the same shape earlier with zero detail, shadowing the better error.

Where

  • packages/coding-agent/src/tools/todo-write.tsvalidateRawTodoArguments returns { outcome: "reject" } with no code in all four branches (root unknown key, op-entry unknown key, done/drop missing target, init-entry unknown key).
  • packages/ai/src/utils/validation.tsRAW_ARGUMENT_REJECTION_MESSAGES only contains the three ask-* deep-interview codes, so any todo rejection falls to the generic byte-for-byte message.

Expected

Raw-argument rejections from todo_write should carry bounded, authority-controlled correction codes (the mechanism added for the ask-tool codes) so the surfaced error names the violated rule, e.g.:

  • unknown root/op/init-entry key → list the accepted keys
  • done/drop without task/phase → state that a target is required and that items is append-only

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions