nautechsystems/nautilus_trader · error · anyhow::Error
Instances must have encode_record_batch_py method
Error message
Instances must have encode_record_batch_py method
What it means
When encoding a custom data class to an Arrow RecordBatch via py_encode_custom_data_to_record_batch, instances are expected to expose a Python method encode_record_batch_py. If the registered Python data class lacks it, the function bails. This enforces the EncodeToRecordBatch contract on user-defined custom data types.
Source
Thrown at crates/model/src/python/data/mod.rs:422
py_batch.call_method1(
"_export_to_c",
(
(&raw mut ffi_array as usize),
(&raw mut ffi_schema as usize),
),
)?;
let schema = std::sync::Arc::new(arrow::datatypes::Schema::try_from(&ffi_schema)?);
let struct_array_data = unsafe {
arrow::ffi::from_ffi_and_data_type(
ffi_array,
arrow::datatypes::DataType::Struct(schema.fields().clone()),
)?
};
let struct_array = arrow::array::StructArray::from(struct_array_data);
Ok(arrow::record_batch::RecordBatch::from(&struct_array))
} else {
anyhow::bail!("Instances must have encode_record_batch_py method")
}
})
}
#[cfg(all(feature = "python", feature = "arrow"))]
fn pyarrow_schema_to_arrow_schema(
py_schema: &pyo3::Bound<'_, pyo3::PyAny>,
) -> PyResult<arrow::datatypes::Schema> {
let mut ffi_schema = arrow::ffi::FFI_ArrowSchema::empty();
py_schema.call_method1("_export_to_c", ((&raw mut ffi_schema as usize),))?;
arrow::datatypes::Schema::try_from(&ffi_schema)
.map_err(|e| to_pyvalue_err(format!("Failed to import PyArrow schema: {e}")))
}
/// Decodes `RecordBatch` to `CustomData` via Python `decode_record_batch_py`.
#[allow(unsafe_code)]
#[cfg(all(feature = "python", feature = "arrow"))]
fn py_decode_record_batch_to_custom_data(View on GitHub (pinned to 18893faf8b)
Solutions
- Define the custom data class using the nautilus custom data macro/base class so encode_record_batch_py is generated.
- Add or restore the encode_record_batch_py method to the class implementing its Arrow schema/batch encoding.
- Check library version migration notes: the Rust serialization path requires this method where the old path may not have.
- Register the class via register_custom_data_class only after the method exists (e.g. assert hasattr(cls, 'encode_record_batch_py')).
Example fix
# before
@customdataclass
class MyData(Data): # lacks batch encoder
...
# after
class MyData(Data):
@classmethod
def encode_record_batch_py(cls, items):
return MyDataEncoder.items_to_record_batch(items) # matches declared arrow schema Defensive patterns
Strategy: type-guard
Validate before calling
# Python: check before registering
if not hasattr(MyData, "encode_record_batch_py"):
raise TypeError("MyData must implement encode_record_batch_py before register_custom_data_class") Type guard
def has_batch_encoder(cls) -> bool:
return callable(getattr(cls, "encode_record_batch_py", None)) Try / catch
try:
register_custom_data_class(MyData)
except Exception as e:
logging.error("custom data registration failed: %s", e) Prevention
- Always define custom data via the nautilus custom data macro/base class.
- Check migration notes after upgrading nautilus versions.
- Smoke-test register + encode round-trip for each custom type in CI.
- Don't strip generated methods when subclassing.
When it happens
Trigger: register_custom_data_class called with a Python class whose instances do not implement encode_record_batch_py — e.g. a plain dataclass not decorated/registered through the nautilus custom data macro, or a class defining only a module-level encode function.
Common situations: Python users subclassing nautilus_trader.model.custom without using the required custom data base/macro; renaming or removing encode_record_batch_py after a library version upgrade; mixing Cython and Rust code paths where only one defines the method.
Related errors
- Python object has no to_json() method or __dict__ attribute
- Expected {}, was different type
- Failed to convert batched deltas to Python: {e}
- Failed to convert to Python: {e}
- Failed to create list: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1948091cbd01f4c5.
Report an issue: GitHub.