Skip to content

todowrite:tool call parameter error #10813

Closed as not planned
Closed as not planned

Description

@jerrod-ji

Description

~ Updating todos...
Error: The todowrite tool was called with invalid arguments: [
{
"expected": "array",
"code": "invalid_type",
"path": [
"todos"
],
"message": "Invalid input: expected array, received string"
}
].
Please rewrite the input so it satisfies the expected schema.

Plugins

No response

OpenCode version

No response

Steps to reproduce

No response

Screenshot and/or share link

No response

Operating System

No response

Terminal

No response

Activity

  1. github-actions commented on Jan 27, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if none of these address your specific case.

  2. eliawk commented on Mar 18, 2026

    @eliawk

    same issue

  3. leohidalgo commented on Mar 21, 2026

    @leohidalgo

    Workaround

    .opencode/plugins/todo-fix-plugin.ts

    export const TodoFixPlugin = async (ctx) => {
      return {
        "tool.execute.before": async (input, output) => {
          if (input.tool === "todowrite" && typeof output.args.todos === "string") {
            output.args.todos = JSON.parse(output.args.todos)
          }
        }
      }
    }
  4. removed
    bugSomething isn't working
    on May 3, 2026
  5. edikid commented on Jul 1, 2026

    @edikid

    Still reproduces on opencode 1.17.11, and a heads-up for anyone landing here: the tool.execute.before → JSON.parse(todos) plugin workaround posted earlier in this thread no longer works on current opencode.

    I instrumented a bare version of that workaround (only tool.execute.before, nothing else) and confirmed with markers that for a stringified todos the hook never fires — the call is rejected at argument validation before execute.before runs:

    EXECUTE_BEFORE todosType=string : 0   # stringified calls never reach execute.before
    EXECUTE_BEFORE todosType=object : 1   # only native-array calls do
    

    Why it used to work and now doesn't: the error format in this thread changed from the Zod style (code: "invalid_type", "Invalid input: expected array, received string") to SchemaError(Expected array, got "<string>"). Tool-argument validation moved from Zod to Effect Schema, and it now runs ahead of tool.execute.before, so no plugin can repair the args in time.

    For completeness, none of the plugin hooks can fix this on 1.17.11:

    • tool.definition overriding a built-in tool's parameters/jsonSchema is not used for validation (verified by instrumentation: the override's validate is never called for the built-in todowrite).
    • tool.execute.before runs after validation (markers above).
    • A shadow/custom tool can't replace todowrite because the SDK exposes only GET /session/{id}/todo (no write API), so a plugin can't update todo state.

    Trigger (detailed writeup in #34652): Claude via the native Anthropic provider intermittently emits nested array tool args as JSON strings; OpenAI/function-calling models don't. It is intermittent and not size-gated — even an empty array [] has been observed arriving as "[]".

    Suggested fix: coerce a stringified tool-arg back to the expected type during tool-arg decoding (scoped strictly so it can't mask unrelated errors), or let plugin tool.definition overrides drive validation for built-in tools so the ecosystem can patch provider quirks without a core change.

  6. edikid commented on Jul 1, 2026

    @edikid

    Quick confirming update from #34652: retested today on the latest opencode (1.17.12) with a newer Claude model (claude-sonnet-5, not the Opus I originally tested) — still reproduces. Same intermittent, non-size-gated pattern (3 consecutive todowrite calls in a fresh session: 7-item payload succeeded, 8-item and even a 1-item payload both failed with the same SchemaError).

    So this isn't an Opus-only quirk and it isn't fixed in the current release. Full evidence and the suggested fix are in #34652.

  7. github-actions commented on Aug 31, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions