Skip to content

File flush on with-exit / teardown swallows backend write_file errors (only explicit .close() surfaces them) #84

Description

@ivarvong

Summary

When a file write is flushed during with-block exit or at interpreter teardown (an unclosed file), Pyex does not propagate an error returned by the filesystem backend's write_file/4. The error is silently swallowed, so a write that actually failed reports success — exit code 0, no exception — and the data is silently lost.

Only an explicit .close() currently surfaces the backend error.

Repro (with a backend whose write_file/4 can fail)

Using a Pyex.Filesystem backend where write_file/4 returns {:error, %VFS.Error{kind: :eio, message: "..."}} for an oversized value:

# 1. explicit close — error SURFACES (correct)
f = open("big.bin", "w")
f.write("x" * 6_000_000)
f.close()                      # -> raises IOError: ... value too large

# 2. with-block — error SWALLOWED (bug)
with open("big.bin", "w") as f:
    f.write("x" * 6_000_000)   # __exit__ closes, but the backend error is dropped
print("no exception")          # <-- this prints

# 3. no close — error SWALLOWED (bug)
open("big.bin", "w").write("x" * 6_000_000)
print("no exception")          # <-- this prints
  • Expected: cases 2 and 3 raise the same IOError as case 1 (the backend rejected the write).
  • Actual: cases 2 and 3 complete with exit_code 0 and no exception; the file is never written.

Why it matters

A Filesystem backend can legitimately reject a write (size limit, quota, permissions, I/O failure). Models overwhelmingly write with with open(...) as f: or a bare open(...).write(...) rather than an explicit .close(), so in practice the failure is invisible to the running program — it believes its data was saved when it was silently dropped.

Expected fix

  • with exit (__exit__) should propagate any error from the close/flush of the managed file.
  • Flushing an unclosed file at end-of-run should at minimum surface the backend error (raise, or route it to stderr / a non-zero exit) rather than discarding it.

The backend's write_file/4 already returns the error; Pyex just needs to honor it on the flush paths, not only on explicit .close().

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