astrid-runtime/astrid · error · io::Error
staged content writer is closed
Error message
staged content writer is closed
What it means
The staged content writer was used after being closed, so the library returns a BrokenPipe io::Error. The writer's close operation releases its reservation (reserved_identifiers removal), and any subsequent operation has no valid backing state, so it fails rather than silently dropping data.
Solutions
- Remove the write call that occurs after close(), or move it before closing
- Restructure code so the writer is consumed in a linear order: write all data, then close once
- Wrap the writer so Rust ownership prevents reuse after close (consume self in close)
- Check application logic for double-close paths (error + success cleanup both closing)
Example fix
// before writer.write_all(&chunk)?; // after close() writer.close()?; writer.write_all(&more)?; // after writer.write_all(&chunk)?; writer.write_all(&more)?; writer.close()?;
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: track closed state in a wrapper
struct GuardedWriter { w: Option<StagedContentWriter> }
impl GuardedWriter {
fn write(&mut self, b: &[u8]) -> io::Result<()> {
match &mut self.w { Some(w) => w.write_all(b), None => Ok(()) } // no-op after close
}
} Type guard
fn is_open(w: &StagedWriterHandle) -> bool { !w.is_closed() } // expose/check a closed flag before use Try / catch
match writer.write_all(&data) {
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => { /* writer already closed: drop or reopen */ }
other => other?,
} Prevention
- Consume the writer in close(self) so the compiler prevents later use
- Enforce linear write-then-close flow in one function or scope
- Never store writers in long-lived structs across close points
- Add debug_assert!(!closed) in wrappers around the writer
When it happens
Trigger: Calling any write/flush method on a StagedContentWriter after close() has been called, e.g. writing in two phases where the second write happens after an early close, or reusing a stored writer handle after the close path ran.
Common situations: Wrapping the writer in a scope where close is called then more bytes are appended; double-close followed by use; holding the writer in a struct and using it after a cleanup routine closed it.
Related errors
- audit read failed
- destination.as_str()
- invalid Astrid volume record length at
- invalid interior Astrid volume record length at
- non-UTF-8 region name
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/ae2d9e99b18c0160.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-storage/src/principal_state/staging/writer.rs:162
fn drop(&mut self) {
if self.preserve_on_drop {
return;
}
self.file.take();
if let Some(path) = self.path.take() {
let _ = std::fs::remove_file(path);
}
self.area
.inner
.seal_order
.lock()
.reserved_identifiers
.remove(&self.id);
}
}
fn closed_writer() -> std::io::Error {
std::io::Error::new(
std::io::ErrorKind::BrokenPipe,
"staged content writer is closed",
)
}
View on GitHub (pinned to affd8760f4)