Summary
build_mdio_header_type cannot build a header dtype for the SEG-Y rev 2 / rev 2.1 standard trace header, so those revisions cannot be ingested at all. The blocker is a single field.
Reproduction
from segy.standards import get_segy_standard
from mdio.segy.utilities import build_mdio_header_type
build_mdio_header_type(get_segy_standard(2))
ValueError: Unsupported numpy dtype 'bytes64' for conversion to ScalarType.
Identical for get_segy_standard(2.1).
Measured on multidimio==1.2.1, segy==0.6.0, zarr==3.3.0, numpy==2.5.2, Python 3.12.13.
Cause
The rev 2 standard declares trace_header_name at byte 233 as an 8-character string:
>>> f = next(x for x in get_segy_standard(2).trace.header.fields if x.byte == 233)
>>> f.name, f.format
('trace_header_name', <ScalarType.STRING8: 'S8'>)
It is the only non-integer field in the 240-byte trace header, and to_structured_type has no ScalarType mapping for numpy's S8 / bytes64.
Why this is worth fixing rather than working around
rev 2 and rev 2.1 are the two revisions whose standard trace header already covers all 240 bytes with no gaps — the easiest revisions to persist faithfully — and they are the two that cannot be ingested. Replacing the field locally with eight uint8 fields lets the ingest run and the resulting store read back correctly, so nothing else in the pipeline objects to rev 2; it is this one dtype.
We are not patching around it: reaching into a pinned dependency is not something our project permits, so rev 2 / 2.1 are currently recorded as unsupported.
Suggested fix
Add a fixed-length byte-string ScalarType and map numpy S<n> to it in to_structured_type. Zarr v3 has fixed_length_utf32, and numcodecs/zarr already handle fixed-length bytes, so there is a representable target.
A narrower alternative that would also unblock ingestion: fall back to n × uint8 for a fixed-width string field, with the field name preserved as metadata. That loses the string typing but keeps the bytes, which for a header field is usually what matters.
Context
Found while probing SEG-Y revision coverage for a conversion validator that checks all 240 trace-header bytes survive ingestion. Happy to open a PR if a preferred direction is indicated.
Summary
build_mdio_header_typecannot build a header dtype for the SEG-Y rev 2 / rev 2.1 standard trace header, so those revisions cannot be ingested at all. The blocker is a single field.Reproduction
Identical for
get_segy_standard(2.1).Measured on
multidimio==1.2.1,segy==0.6.0,zarr==3.3.0,numpy==2.5.2, Python 3.12.13.Cause
The rev 2 standard declares
trace_header_nameat byte 233 as an 8-character string:It is the only non-integer field in the 240-byte trace header, and
to_structured_typehas noScalarTypemapping for numpy'sS8/bytes64.Why this is worth fixing rather than working around
rev 2 and rev 2.1 are the two revisions whose standard trace header already covers all 240 bytes with no gaps — the easiest revisions to persist faithfully — and they are the two that cannot be ingested. Replacing the field locally with eight
uint8fields lets the ingest run and the resulting store read back correctly, so nothing else in the pipeline objects to rev 2; it is this one dtype.We are not patching around it: reaching into a pinned dependency is not something our project permits, so rev 2 / 2.1 are currently recorded as unsupported.
Suggested fix
Add a fixed-length byte-string
ScalarTypeand map numpyS<n>to it into_structured_type. Zarr v3 hasfixed_length_utf32, andnumcodecs/zarralready handle fixed-length bytes, so there is a representable target.A narrower alternative that would also unblock ingestion: fall back to
n×uint8for a fixed-width string field, with the field name preserved as metadata. That loses the string typing but keeps the bytes, which for a header field is usually what matters.Context
Found while probing SEG-Y revision coverage for a conversion validator that checks all 240 trace-header bytes survive ingestion. Happy to open a PR if a preferred direction is indicated.