influxdata/influxdb · error · CodecError
failed to obtain writer handle clone
Error message
failed to obtain writer handle clone: {0} What it means
CodecError::CloneSink, raised when cloning a handle to the provided write sink (a std::io::Error occurs while try_clone-ing the writer). The library needs a second handle to the sink (e.g. for buffered writing) and the sink type does not support cloning.
Solutions
- Use a sink type that supports try_clone, such as std::fs::File or std::io::Cursor
- Write to an in-memory buffer (Vec<u8>/Cursor) and upload the bytes afterwards instead of a non-cloneable stream
- Fix the custom writer wrapper to implement try_clone correctly
- Check the inner std::io::Error for the OS-level reason (e.g. EMFILE, bad fd)
Example fix
// before: non-cloneable sink let sink = MyStreamWrapper::new(sock); serialize_to_parquet(sink)?; // CloneSink error // after let buf = std::io::Cursor::new(Vec::new()); serialize_to_parquet(buf)?; upload(buf.into_inner());
Defensive patterns
Strategy: type-guard
Validate before calling
// only pass sinks that can be cloned
fn assert_cloneable<S: Write + Seek + TryClone>(_: &S) {}
// or pre-check: use File/Cursor rather than custom wrappers Type guard
fn is_cloneable_sink<S: Write + Seek>(s: &S) -> bool {
// File and Cursor support try_clone; custom wrappers may not
s.is_file() || std::mem::size_of::<*const S>() == std::mem::size_of::<*const std::fs::File>() && s.is_file()
} Try / catch
match res {
Err(CodecError::CloneSink(e)) => {
error!(%e, "sink not cloneable; use File/Cursor or an in-memory buffer")
}
other => other?,
} Prevention
- Prefer std::fs::File or io::Cursor<Vec<u8>> as the write sink
- Avoid wrapping sinks in custom types without try_clone support
- Test the write path with the exact sink type used in production
When it happens
Trigger: Passing a Write+Seek sink whose try_clone() fails (e.g. certain non-cloneable file/socket wrappers) into the Parquet serialisation entry point that clones the handle.
Common situations: Wrapping a writer in a custom type without try_clone support, using a pipe or socket that cannot duplicate its descriptor, or the underlying fd being closed/unavailable.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/682d57381239ec68.
Report an issue: GitHub.
Appendix: source
Thrown at core/parquet_file/src/serialize.rs:84
NoRows,
/// A DataFusion error during the plan execution.
///
/// Of note: a ResourcesExhaused error likely means the buffer
/// used for parquet data became too large.
#[error(transparent)]
DataFusion(Box<DataFusionError>),
/// Serialising the [`IoxMetadata`] to protobuf-encoded bytes failed.
#[error("failed to serialize iox metadata: {0}")]
MetadataSerialisation(#[from] prost::EncodeError),
/// Writing the parquet file failed with the specified error.
#[error("failed to build parquet file: {0}")]
Writer(#[from] ParquetError),
/// Attempting to clone a handle to the provided write sink failed.
#[error("failed to obtain writer handle clone: {0}")]
CloneSink(std::io::Error),
}
impl From<CodecError> for DataFusionError {
fn from(value: CodecError) -> Self {
match value {
e @ (CodecError::NoRecordBatches
| CodecError::NoRows
| CodecError::MetadataSerialisation(_)
| CodecError::CloneSink(_)) => Self::External(Box::new(e)),
CodecError::Writer(e) => Self::ParquetError(Box::new(e)),
CodecError::DataFusion(e) => *e,
}
}
}
impl From<crate::writer::Error> for CodecError {
fn from(value: crate::writer::Error) -> Self {View on GitHub (pinned to 06200ef96b)