tokio-rs/tokio · error · io::Error
other file operation is pending, call poll_complete before s
Error message
other file operation is pending, call poll_complete before start_seek
What it means
Runtime error from `File::start_seek` (file.rs:681). Tokio's `File` refuses to begin a seek while it is in `State::Busy` — a prior read/write operation has not yet completed. The API requires the previous operation to be drained via `poll_complete` before a new `start_seek`. This is an API-usage violation, not an I/O failure.
Source
Thrown at tokio/src/fs/file.rs:681
if let Ok(pos) = result {
inner.pos = pos;
}
continue;
}
}
}
}
}
}
}
impl AsyncSeek for File {
fn start_seek(self: Pin<&mut Self>, mut pos: SeekFrom) -> io::Result<()> {
let me = self.get_mut();
let inner = me.inner.get_mut();
match inner.state {
State::Busy(_) => Err(io::Error::new(
io::ErrorKind::Other,
"other file operation is pending, call poll_complete before start_seek",
)),
State::Idle(ref mut buf_cell) => {
let mut buf = buf_cell.take().unwrap();
// Factor in any unread data from the buf
if !buf.is_empty() {
let n = buf.discard_read();
if let SeekFrom::Current(ref mut offset) = pos {
*offset += n;
}
}
let std = me.std.clone();
inner.state = State::Busy(spawn_blocking(move || {View on GitHub (pinned to 625954f365)
Solutions
- Fully `await` the previous read/write operation before issuing a seek on the same `File`.
- Prefer the `AsyncSeekExt`/`AsyncReadExt`/`AsyncWriteExt` combinators which enforce the operation ordering.
- Do not share one `File` across concurrent tasks; serialize access through a single owner or a channel.
- If polling manually, call `poll_complete` to finish the pending op before `start_seek`.
Example fix
// before: seeking while a read future is still pending let n = file.read(&mut buf).await?; // ensure this completes first file.seek(SeekFrom::Start(0)).await?; // OK only after the read resolved // after: always await prior ops before seeking (serialize on one owner) let n = file.read(&mut buf).await?; file.seek(SeekFrom::Start(0)).await?; file.write(&data).await?;
Defensive patterns
Strategy: validation
Validate before calling
// Enforce single-owner access to the File; never start a seek while a // read/write future is still pending. Await each op to completion first. // (Compile-time discipline; no runtime check exists inside File itself.)
Prevention
- Fully `await` each read/write before seeking on the same `File`.
- Never share one `File` across concurrent tasks; serialize through a single owner.
- Prefer the `AsyncReadExt`/`AsyncWriteExt`/`AsyncSeekExt` combinators over manual polling.
- If polling manually, always call `poll_complete` before `start_seek`.
When it happens
Trigger: Calling `AsyncSeekExt::seek` (which calls `start_seek`) on a `File` while a previous `poll_read`/`poll_write` operation is still pending — e.g. interleaving seeks with an in-flight read/write future on the same `File`, or sharing one `File` across tasks without serialization.
Common situations: Mixing `AsyncReadExt`/`AsyncWriteExt` and `AsyncSeekExt` calls on the same `File` without fully awaiting each; manually polling the `File`; sharing a `File` across tasks concurrently (Tokio files are not `Sync`-shareable for concurrent ops).
Related errors
- background task failed
- background task failed
- bytes remaining on stream
- failed to write frame to transport
- frame size too big
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/47726d0ce53f05a5.
Report an issue: GitHub.