{"record":{"id":"5c2d77a60cb9d1b6","repo":"docling-project/docling","slug":"input-ends-inside-name-r-end-offset-of-siz","errorCode":null,"errorMessage":"Input ends inside {name!r}: {end - offset} of {size} bytes left.","messagePattern":"Input ends inside (.+?): (.+?) of (.+?) bytes left\\.","errorType":"exception","errorClass":"EbcdicDecodeError","httpStatus":null,"severity":"error","filePath":"docling/backend/ebcdic_backend.py","lineNumber":182,"sourceCode":"\n        record = layout.select(record_type)\n        if record is None:\n            raise EbcdicDecodeError(\n                f\"No record layout matches record type {record_type!r}.\"\n            )\n\n        size = record.size if length is None else length - layout.prefix_size\n        if size < 0:\n            raise EbcdicDecodeError(\n                f\"Record length {length} is shorter than the \"\n                f\"{layout.prefix_size}-byte record prefix.\"\n            )\n        return record, size, offset\n\n    @staticmethod\n    def _take(data: bytes, offset: int, size: int, end: int, name: str) -> bytes:\n        if offset + size > end:\n            raise EbcdicDecodeError(\n                f\"Input ends inside {name!r}: {end - offset} of {size} bytes left.\"\n            )\n        return data[offset : offset + size]\n\n    def _decode_record(self, record: EbcdicRecordLayout, body: bytes) -> list[str]:\n        values: list[str] = []\n        offset = 0\n        for field in record.fields:\n            chunk = body[offset : offset + field.size]\n            offset += field.size\n            if field.type is not EbcdicFieldType.SKIP:\n                values.append(str(self._decoder.decode(chunk, field)))\n        return values\n\n\nclass EbcdicDocumentBackend(DeclarativeDocumentBackend):\n    \"\"\"Declarative backend converting EBCDIC data files to `DoclingDocument`.\n","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/backend/ebcdic_backend.py#L164-L200","documentation":"EbcdicDecodeError raised by the _take helper when the input buffer ends before a prefix field (record length or record type) can be read in full: offset + size exceeds the end of the remaining data. The message names the field and says how many of the expected bytes remain. It indicates truncation or prefix misalignment — either the file was cut short, or record framing drifted so a prefix is being read at a bogus offset.","triggerScenarios":"A truncated EBCDIC file (partial transfer, fixed max_records cutting mid-record, network cut); a wrong record length earlier causing the next prefix read to land past the end; a layout whose prefix fields are larger than the real prefix; final record without the declared length/type prefix.","commonSituations":"FTP/transfers in text mode corrupting record boundaries and truncating trailing bytes; fixed-block files sliced incorrectly; upstream job writing a partial last block; layouts assuming a length prefix on records that actually have none for the final segment.","solutions":["Verify the file size against the expected record structure (count x size for fixed-length records) and re-transfer the file in binary mode.","If a length field misdecode is the root cause, fix the record_length_field declaration first (see the negative-size error) — misframing cascades into this error.","Use EbcdicBackendOptions.max_records to stop at a known-good boundary while debugging, and check whether the error persists on the pristine file.","Confirm prefix fields (sizes and presence) match the actual feed format; remove record_length_field/record_type_field declarations if the feed has no such prefix."],"exampleFix":"# before\n# file transferred via FTP text mode -> truncated/corrupt record boundaries\nconv.convert(Path('feed.dat'))  # Input ends inside 'LEN': 1 of 2 bytes left\n\n# after\n# re-transfer in binary mode, then verify expected byte count\nexpected = num_records * record_size\nassert Path('feed.dat').stat().st_size == expected\nconv.convert(Path('feed.dat'))","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef size_consistent(path: Path, record_size: int | None, declared_total: int | None) -> bool:\n    n = path.stat().st_size\n    if record_size is not None and n % record_size != 0:\n        return False  # truncated fixed-record file\n    if declared_total is not None and n != declared_total:\n        return False\n    return True","typeGuard":null,"tryCatchPattern":"from docling.backend.ebcdic_backend import EbcdicDecodeError\ntry:\n    conv.convert(src, pipeline_options=opts)\nexcept EbcdicDecodeError as e:\n    if \"Input ends inside\" in str(e):\n        retransfer_binary(src)  # truncation: refetch, do not parse a partial file\n    else:\n        raise","preventionTips":["Transfer mainframe files in binary mode only.","Validate file size modulo record size for fixed-length feeds before conversion.","Treat mid-record truncation as a transfer defect; never parse partial files."],"tags":["ebcdic","truncation","layout","transfer"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}