docling-project/docling · error · EbcdicDecodeError

Cannot decode field {field.name!r} of type {field.type.value

Error message

Cannot decode field {field.name!r} of type {field.type.value} from {data.hex()!r}.

What it means

EbcdicDecodeError (a DocumentLoadError subclass) raised when decoding a single field's bytes fails: the per-type decoder (string via the configured codec, packed/zoned decimal digit handling, binary int conversion) raised ArithmeticError, LookupError, UnicodeError, or ValueError. The message names the field, its declared type, and the raw hex bytes, which is exactly what you need to tell a layout mismatch (bytes don't fit the declared type) from an encoding problem.

Source

Thrown at docling/backend/ebcdic_backend.py:85

        except LookupError as exc:
            raise DocumentLoadError(f"Unknown EBCDIC codec {encoding!r}.") from exc
        self._strip_control_characters = strip_control_characters
        self._decoders: dict[EbcdicFieldType, Callable[[bytes], _DecodedValue]] = {
            EbcdicFieldType.STRING: self._string,
            EbcdicFieldType.INTEGER: lambda data: self._binary(data, signed=True),
            EbcdicFieldType.UNSIGNED_INTEGER: lambda data: self._binary(
                data, signed=False
            ),
            EbcdicFieldType.PACKED_DECIMAL: self._packed_decimal,
            EbcdicFieldType.ZONED_DECIMAL: self._zoned_decimal,
        }

    def decode(self, data: bytes, field: EbcdicField) -> _DecodedValue:
        """Decode the bytes of one field as described by its layout."""
        try:
            value = self._decoders[field.type](data)
        except (ArithmeticError, LookupError, UnicodeError, ValueError) as exc:
            raise EbcdicDecodeError(
                f"Cannot decode field {field.name!r} of type {field.type.value} "
                f"from {data.hex()!r}."
            ) from exc
        if isinstance(value, int) and field.scale:
            return Decimal(value).scaleb(-field.scale)
        return value

    def _string(self, data: bytes) -> str:
        text, _ = self._decode_text(data)
        if self._strip_control_characters:
            text = _CONTROL_CHARACTERS.sub("", text)
        return text.strip()

    @staticmethod
    def _binary(data: bytes, signed: bool) -> int:
        return int.from_bytes(data, byteorder="big", signed=signed)

    @staticmethod

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Use the hex bytes in the message: check whether they are plausible for the declared type (e.g. packed decimal must end in a valid sign nibble C/D/F).
  2. Re-derive the layout from the authoritative copybook, paying attention to COMP/COMP-3 usage, SYNC padding, and REDEFINES.
  3. If UnicodeError is chained (check e.__cause__), switch EbcdicBackendOptions.encoding to the correct code page (cp037 vs cp500 etc.).
  4. Verify preceding field sizes — a wrong size earlier shifts every later field and produces this error on an innocent field.

Example fix

# before (layout mismatch)
opts = EbcdicBackendOptions(
    layout=EbcdicLayout(
        records=[EbcdicRecordLayout(name='hdr', fields=[
            EbcdicField(name='AMOUNT', type=EbcdicFieldType.ZONED_DECIMAL, size=5),
        ])],
    ),
    encoding='cp037',
)
# AMOUNT is really COMP-3 packed -> decode error

# after
EbcdicField(name='AMOUNT', type=EbcdicFieldType.PACKED_DECIMAL, size=3),  # match copybook
Defensive patterns

Strategy: try-catch

Validate before calling

# Decode a sample record with your layout before batch runs:
def layout_smokescreen(layout, sample_bytes: bytes) -> list[str] | None:
    try:
        return decode_record(layout, sample_bytes)  # your thin wrapper over the backend
    except Exception:
        return None

if layout_smokescreen(layout, first_record_bytes) is None:
    raise ConfigError("EBCDIC layout does not match sample data")

Try / catch

from docling.backend.ebcdic_backend import EbcdicDecodeError
try:
    conv.convert(src, pipeline_options=opts)
except EbcdicDecodeError as e:
    field, hexbytes = parse_message(str(e))  # field name + hex payload are embedded
    log.error("layout mismatch at %s bytes=%s cause=%r", field, hexbytes, e.__cause__)
    quarantine(src)

Prevention

When it happens

Trigger: A layout whose field offsets/sizes/types do not match the actual data: a field declared PACKED_DECIMAL whose bytes have an invalid sign nibble; a STRING field containing bytes unmappable in the configured codec (UnicodeError); an INTEGER field wider than expected; field boundaries shifted because an earlier field's size is wrong.

Common situations: Hand-written layout files transcribed from a COBOL copybook with an off-by-one; copybook REDEFINES or COMP-3 packing not translated correctly; using the wrong EBCDIC code page for the site's country; files from a different mainframe system version than the layout documents.

Related errors


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