docling-project/docling · error · EbcdicDecodeError

No record layout matches record type {record_type!r}.

Error message

No record layout matches record type {record_type!r}.

What it means

EbcdicDecodeError raised during record framing: the backend decoded the record-type prefix field and called layout.select(record_type), but no EbcdicRecordLayout in the layout declares that type value, so it cannot know how to parse the record body. The message shows the decoded record_type value — comparing it with your layout's declared record types is the whole debugging step.

Source

Thrown at docling/backend/ebcdic_backend.py:167

        self, data: bytes, offset: int, end: int
    ) -> tuple[EbcdicRecordLayout, int, int]:
        """Consume the record prefix and resolve the schema and body size."""
        layout = self._layout
        length: Union[int, None] = None
        record_type: Union[str, None] = None

        if (field := layout.record_length_field) is not None:
            chunk = self._take(data, offset, field.size, end, field.name)
            length = int(self._decoder.decode(chunk, field))
            offset += field.size
        if (field := layout.record_type_field) is not None:
            chunk = self._take(data, offset, field.size, end, field.name)
            record_type = str(self._decoder.decode(chunk, field))
            offset += field.size

        record = layout.select(record_type)
        if record is None:
            raise EbcdicDecodeError(
                f"No record layout matches record type {record_type!r}."
            )

        size = record.size if length is None else length - layout.prefix_size
        if size < 0:
            raise EbcdicDecodeError(
                f"Record length {length} is shorter than the "
                f"{layout.prefix_size}-byte record prefix."
            )
        return record, size, offset

    @staticmethod
    def _take(data: bytes, offset: int, size: int, end: int, name: str) -> bytes:
        if offset + size > end:
            raise EbcdicDecodeError(
                f"Input ends inside {name!r}: {end - offset} of {size} bytes left."
            )
        return data[offset : offset + size]

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Compare the record_type value in the message with the type values declared on your records — add a matching EbcdicRecordLayout (or extend its type list) if the data legitimately contains that variant.
  2. If the value looks like mojibake, fix record_type_field: correct size, offsets, and encoding (e.g. decode via zoned decimal if the field is numeric).
  3. Confirm record_length_field handling: a wrong length shifts the offset at which the type is read.
  4. Print the raw prefix bytes around the failing record and reconcile them against the copybook.

Example fix

# before
layout = EbcdicLayout(
    records=[EbcdicRecordLayout(name='detail', record_types={'D'})],
    record_type_field=EbcdicField(name='RT', type=EbcdicFieldType.STRING, size=1),
)
# data contains 'H' header records -> No record layout matches record type 'H'

# after
records=[
    EbcdicRecordLayout(name='header', record_types={'H'}, fields=[...]),
    EbcdicRecordLayout(name='detail', record_types={'D'}, fields=[...]),
]
Defensive patterns

Strategy: try-catch

Validate before calling

# Enumerate record types present in data vs declared in layout:
def undeclared_record_types(layout, data: bytes) -> set[str]:
    declared = set().union(*(r.record_types for r in layout.records))
    seen = set()
    for rec_start in iter_record_starts(data):  # your framing walk
        seen.add(decode_type_field(data, rec_start))
    return seen - declared  # non-empty predicts this error

Try / catch

from docling.backend.ebcdic_backend import EbcdicDecodeError
try:
    conv.convert(src, pipeline_options=opts)
except EbcdicDecodeError as e:
    if "No record layout matches" in str(e):
        rt = extract_record_type(str(e))
        add_record_variant_to_layout(opts.layout, rt)  # then retry
    else:
        raise

Prevention

When it happens

Trigger: Data contains a record type token not declared in layout.records (new record variant, regional record, or versioned format); the record_type_field is mis-declared (wrong size/offset/type/encoding) so a valid type decodes to garbage; records where the type field overlaps other data because offsets shifted.

Common situations: Layout built from an old copybook while the feed added new record types; record_type declared as STRING but stored as zoned/packed numeric (or vice versa); fixed-vs-variable length prefix confusion causing the type bytes to be read from the wrong position.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/e4369c4454568f92. Report an issue: GitHub.