Repository navigation
Description
Describe the bug
Two input-handling gaps make write calls report success while changing nothing:
-
Empty strings are treated as "not provided". In
issue_writemethod: update,title: ""andbody: ""are skipped, and the call returns success with no change. A body can't be cleared, and an empty title is not refused.update_pull_requestwithtitle: ""sends the edit and gets a REST 422 (PullRequest.title (missing_field)), so the two tools behave differently. -
Unknown or misspelled parameters are silently dropped. No write tool's input schema sets
additionalProperties: false(all 19 write tools in the default toolsets, checked viatools/list), and the typed decode ignores extra keys. Examples:issue_writeupdate with onlylabelzreturns success and changes nothing.delete_filewithshadeletes without any check (see the separate delete_file issue).actions_listwithper_page(the schema saysperPage) uses the default page size.
update_pull_requestwith only a misspelled field (titel) does fail, but only because its "No update parameters provided." guard (pullrequests.go:1080) catches the empty update.
Related: #3605 / PR #3630 handle misspelled required names (pull_number vs pullNumber) by adding aliases. This issue is about optional fields, where nothing fails.
Same class on the read side: #3316 (open; pull_request_read silently ignores inapplicable pagination params; PRs #3317 and #3336). The *Provided flags for labels/assignees came from #2596 / PR #2600.
Code (main 99d6d65, unchanged since v2.1.0): pkg/github/issues.go:3415-3421 (if title != "" / if body != ""); labels and assignees already use explicit "provided" flags (:3423). Write-tool input schemas have no AdditionalProperties set.
Affected version
v2.1.0 (image sha256:f6056fc1…0f8a, commit 4bcdcdf) and main nightly (image sha256:48bc16d0…338f, revision 99d6d65).
Steps to reproduce the behavior
- Issue N has title
T, bodyB, labels[c, d].
(123 stands for the issue/PR number.) - Call:
Result:
{"name":"issue_write","arguments":{"method":"update","owner":"OWNER","repo":"REPO","issue_number":123,"body":""}}OK {"id":"…","url":".../issues/N"}. The body is stillB. - Same with
"title":"". Result: OK, and the title is stillT. - Call:
Result: OK, and the labels are still
{"name":"issue_write","arguments":{"method":"update","owner":"OWNER","repo":"REPO","issue_number":123,"labelz":["a"]}}[c, d]. - For comparison,
update_pull_request{"pullNumber":P,"title":""}returnsfailed to update pull request: Validation Failed PullRequest.title (missing_field).
Expected vs actual behavior
Expected:
- An empty
bodyclears the body. An emptytitleis rejected with a clear message. - An unknown parameter is rejected and named (
unknown parameter "labelz"), so the caller can correct it.
Actual: success with no change in each case, so an agent believes the update happened.
Suggested fix: decide presence by key, not by value, for title/body (as LabelsProvided already does). Set additionalProperties: false on write-tool input schemas, or reject unknown keys during the typed decode, at least for write tools.
Logs
issue_write update body="" -> OK {"id":"6277311572","url":".../issues/N"} body unchanged
issue_write update title="" -> OK … title unchanged
issue_write update labelz=["a"] -> OK … labels unchanged
update_pull_request title="" -> ISERROR failed to update pull request: Validation Failed / PullRequest.title (missing_field)
update_pull_request titel="x" -> ISERROR No update parameters provided.
tools/list: additionalProperties unset on all 19 write tools (default toolsets)
Same results on v2.1.0 and main. In an earlier run, issue_write method: create with lables also created the issue without labels. That case was not re-run here, to avoid creating issues.
Found during an independent audit of v2.1.0 on a throwaway org and private test repo. Prepared with AI assistance (Claude Code); reproduced by two independent test runs before filing.
Activity
rafe-walker commentedon Nov 12, 2026
I read #3789 against the steps above. This is from reading the change, not a test run.
titleandbodyare now decided by whether the key is present, following the existingLabelsProvidedpattern.body: ""clears the body (step 2), andtitle: ""returnstitle cannot be empty, omit it to keep the current titleinstead of a silent success (step 3).issue_writeupdate with onlylabelz) would still succeed and change nothing. The same goes forper_pageonactions_list, since write-tool schemas still don't setadditionalProperties: falseand the typed decode still ignores unknown keys. That part touches every write tool, so it may be better as its own change. If that's the preferred split, I'm happy to open a separate issue for it so this PR can close part 1.Happy to re-run the original reproduction once a maintainer is happy with the approach.