Skip to content

fix: BufWriter must not re-poll an already-completed future after an error - #856

Open
arbelonson-source wants to merge 1 commit into
apache:mainfrom
arbelonson-source:fix/810-bufwriter-panic-after-error
Open

arbelonson-source wants to merge 1 commit into
apache:mainfrom
arbelonson-source:fix/810-bufwriter-panic-after-error

Conversation

@arbelonson-source

Copy link
Copy Markdown

Which issue does this PR close?

Closes #810.

Rationale for this change

BufWriter::poll_write, poll_flush, poll_shutdown and the plain-async put() all handle the Prepare/Flush state's inner future the same way: on Ok they move to the next state, on Err they propagate with ? inside ready!(...) (or .await?) without touching self.state. Because ? short-circuits before the state assignment, self.state is left holding the future that just completed. The next call — e.g. close() after a failed write(), exactly the sequence in #810 — polls that finished future again and panics with `async fn` resumed after completion instead of returning an error.

What changes are included in this PR?

  • A terminal BufWriterState::Errored variant. Every site that used to propagate a Prepare/Flush error via ? now transitions into Errored and returns the error explicitly; every state-matching function (poll_write, poll_flush, poll_shutdown, put, abort) gets an Errored arm that returns an error rather than polling anything.
  • abort() treats Errored like Buffer/Prepare (Ok(())): a failed Prepare/Flush future never durably created anything remote to clean up.
  • Three tests that drive a write error through the InMemory store and then call flush, shutdown and abort. With only the production change reverted, the flush and shutdown tests fail with the original panic at the state machine; the abort one already passed and is there to pin that behaviour.

cargo test --lib buffered, cargo fmt --check and cargo clippy --all-targets --all-features -- -D warnings are clean on top of current main (279572e).

Are there any user-facing changes?

Behavioural only: after a failed write, a further flush/shutdown/write on the same BufWriter now returns an Err instead of panicking. No API changes.


Disclosure, as offered on #810 and per the ASF generative-tooling guidance: this change was produced by an autonomous agent (the code by Claude Opus 5, the rebase and re-verification today by Claude Fable 5.1, both via Claude Code) on behalf of the account owner; the commit carries a Generated-by: trailer. Happy to adjust anything.

…error

BufWriter's poll_write/poll_flush/poll_shutdown, and the plain-async put(),
all handled the Prepare/Flush state's inner future the same way: on Ok,
transition state and continue; on Err, propagate the error via `?` inside
`ready!(...)` (or `.await?`) without ever updating `self.state`. Since `?`
short-circuits before the state assignment runs, `self.state` is left
sitting on the same future that just returned Ready -- if write/flush/
shutdown is called again afterward (e.g. calling close() after write()
already failed, as reported), that same, already-completed future gets
polled a second time, which panics with `` `async fn` resumed after
completion `` instead of returning an error.

Adds a terminal `BufWriterState::Errored` variant. Every place that used
to propagate a Prepare/Flush error via `?` now instead transitions into
Errored and returns the error explicitly; every state-matching function
(poll_write, poll_flush, poll_shutdown, put, abort) has a corresponding
Errored arm. abort() treats Errored the same as Buffer/Prepare (Ok(())),
since a failed Prepare/Flush future never durably created anything
remotely to clean up.

Fixes apache#810

Generated-by: Claude Opus 5, via Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BufWriter panic

1 participant