Skip to content

write_file() commits to disk before its own JSON/YAML/TOML syntax check runs — invalid content is written and reported as successful #60525

Description

@neoguyverx

write_file() in tools/file_operations.py calls self._atomic_write(path, content) first, then runs _check_lint_delta() afterward and merely attaches the result to the response. A parse failure never sets the top-level error key, so tools/file_tools.py's write_file_tool()/patch_tool() wrapper — which gates files_modified reporting on not result_dict.get("error") — reports the write as successful even when the content it just wrote doesn't parse.

Confirmed present, byte-for-byte identical gating logic, in tag v2026.6.5 (v0.16.0), tag v2026.7.1 (v0.18.0, current latest), and main as of 2026-07-07. Searched roughly 15 issue-query phrasings; closest existing reports (#57788, #52267, #31657, #33801) are about write-persistence/redaction, not this specific defect.

Real-world impact: on a self-hosted deployment, an agent session wrote syntactically-invalid JSON to a live cron/jobs.json after a redaction pass upstream of the model produced malformed content mid-write. The tool call reported success (lint.status: "error" was present in the same response, but no top-level error key), and the corrupted file went undetected until a later manual audit — both scheduled cron jobs in that file were non-functional in the interim.

Repro sketch:

from tools.environments.local import LocalEnvironment
from tools.file_operations import ShellFileOperations

env = ShellFileOperations(LocalEnvironment(cwd="/tmp"), cwd="/tmp")
result = env.write_file("/tmp/config.json", '{"a": 1,')  # truncated / invalid
# result.error is None, file IS written to disk with invalid JSON

Proposed fix (already implemented and tested against v2026.7.1, happy to open a PR): move the in-process syntax check for JSON/YAML/TOML ahead of _atomic_write() and refuse the write outright on a parse failure — no temp file, no rename, top-level error set so the existing files_modified gating correctly suppresses the report. Deliberately scoped to JSON/YAML/TOML (not .py) since the existing test suite writes non-Python text through *.py paths as generic write-mechanics fixtures (a naive full-LINTERS_INPROC scope broke 3 previously-green tests). 9 new tests (tests/tools/test_write_file_syntax_gate.py), fail-then-pass proven, zero regressions across the full tests/tools/ file-operations surface (196 tests: test_file_operations.py, test_file_write_safety.py, test_file_read_guards.py).

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — major feature broken, no workaroundcomp/toolsTool registry, model_tools, toolsetstool/fileFile tools (read, write, patch, search)type/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions