schema_version = 1
[[case]]
id = "e001_record_length_non_digit"
code = "E001"
variant = "RecordLengthInvalid"
slug = "record_length_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e001_record_length_non_digit.bin"
description = "Leader byte 0 ('0' of '00150') replaced with 'X'."
expected_context = ["record_index", "byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e001_record_length_below_24"
code = "E001"
variant = "RecordLengthInvalid"
slug = "record_length_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e001_record_length_below_24.bin"
description = "Leader bytes 0-4 set to '00010' (decimal 10 < 24-byte minimum)."
expected_context = ["record_index", "byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e002_indicator_count_non_digit"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_indicator_count_non_digit.bin"
description = "Leader byte 10 (indicator count, normally '2') replaced with 'X'."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e002_invalid_record_status"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_invalid_record_status.bin"
description = "Leader byte 5 (record status) is 'x' (not in {a, c, d, n, p})."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_invalid_record_type"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_invalid_record_type.bin"
description = "Leader byte 6 (type of record) is 'q' (not in the documented set)."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_invalid_bibliographic_level"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_invalid_bibliographic_level.bin"
description = "Leader byte 7 (bibliographic level) is 'q' (not in {a, b, c, d, i, m, s})."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_invalid_control_record_type"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_invalid_control_record_type.bin"
description = "Leader byte 8 (control record type) is 'q' (not in {' ', 'a'})."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_invalid_character_coding"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_invalid_character_coding.bin"
description = "Leader byte 9 (character coding) is 'q' (not in {' ', 'a'})."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_indicator_count_not_two"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_indicator_count_not_two.bin"
description = "Leader byte 10 (indicator count) is '3' (digit but MARC 21 requires 2)."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_subfield_code_count_not_two"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_subfield_code_count_not_two.bin"
description = "Leader byte 11 (subfield code count) is '3' (digit but MARC 21 requires 2)."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_invalid_encoding_level"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_invalid_encoding_level.bin"
description = "Leader byte 17 (encoding level) is 'q' (not in {' ', 1-5, 7, 8, u, z})."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_invalid_cataloging_form"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_invalid_cataloging_form.bin"
description = "Leader byte 18 (cataloging form) is 'q' (not in {' ', a, c, i, n, u})."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_invalid_multipart_level"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e002_invalid_multipart_level.bin"
description = "Leader byte 19 (multipart level) is 'q' (not in {' ', a, b, c})."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "bytes_near"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e002_data_base_address_overflow_programmatic"
code = "E002"
variant = "InvalidLeader"
slug = "leader_invalid"
trigger_kind = "programmatic_validator"
description = "Construct Leader with data_base_address = 100_000 and invoke RecordStructureValidator::validate_leader directly."
expected_context = []
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e003_base_address_non_digit"
code = "E003"
variant = "BaseAddressInvalid"
slug = "base_address_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e003_base_address_non_digit.bin"
description = "Leader byte 12 ('0' of base address '00061') replaced with 'X'."
expected_context = ["record_index", "byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e003_base_address_below_24"
code = "E003"
variant = "BaseAddressInvalid"
slug = "base_address_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e003_base_address_below_24.bin"
description = "Leader bytes 12-16 set to '00020' (decimal 20 < 24-byte leader minimum)."
expected_context = ["record_index", "byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e004_base_address_past_record"
code = "E004"
variant = "BaseAddressNotFound"
slug = "base_address_not_found"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e004_base_address_past_record.bin"
description = "Leader bytes 12-16 set to '99999' (> 150-byte record length)."
expected_context = ["record_index", "byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e005_truncated_record"
code = "E005"
variant = "TruncatedRecord"
slug = "truncated_record"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e005_truncated_record.bin"
description = "Record claims 150 bytes; stream ends after 100."
expected_context = ["record_index", "byte_offset", "record_byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e005_truncated_record_lenient"
code = "E005"
variant = "TruncatedRecord"
slug = "truncated_record"
trigger_kind = "parse_iso2709_lenient"
trigger_fixture = "tests/data/error_fixtures/e005_truncated_record.bin"
description = "Same truncated fixture as the strict case; lenient mode pushes E005 onto record.errors instead of raising."
expected_context = ["record_index", "byte_offset", "record_byte_offset"]
recovery_modes = ["lenient"]
wired = true
[[case]]
id = "e006_no_record_terminator"
code = "E006"
variant = "EndOfRecordNotFound"
slug = "end_of_record_not_found"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e006_no_record_terminator.bin"
description = "Final byte (0x1D RECORD_TERMINATOR) replaced with 0x00."
expected_context = ["record_index", "byte_offset", "record_byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e007_io_failure"
code = "E007"
variant = "IoError"
slug = "io_error"
trigger_kind = "io_error"
description = "Reader source errors on the first read (leader boundary); no positional context available."
expected_context = []
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e007_io_failure_parse_path"
code = "E007"
variant = "IoError"
slug = "io_error"
trigger_kind = "io_error_parse_path"
description = "Reader source errors mid-record while reading the data area; IoError carries the in-progress record's context."
expected_context = ["record_index", "byte_offset", "source_name"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e099_recovery_cap_exceeded"
code = "E099"
variant = "FatalReaderError"
slug = "fatal_reader_error"
trigger_kind = "recovery_cap"
description = "Stream of malformed records exceeds MarcReader::with_max_errors(N)."
expected_context = []
recovery_modes = ["lenient", "permissive"]
wired = true
[[case]]
id = "e101_no_field_terminator"
code = "E101"
variant = "DirectoryInvalid"
slug = "directory_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e101_directory_no_terminator.bin"
description = "Byte 60 (FIELD_TERMINATOR 0x1E ending the directory) replaced with '0', producing a partial trailing entry."
expected_context = ["record_index", "byte_offset", "record_byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e101_non_digit_length"
code = "E101"
variant = "DirectoryInvalid"
slug = "directory_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e101_directory_non_digit_length.bin"
description = "Directory entry length field 'X025' (was '0025') for the 100 entry."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "field_tag"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e101_non_ascii_tag"
code = "E101"
variant = "DirectoryInvalid"
slug = "directory_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e101_non_ascii_tag.bin"
description = "Directory entry 1 tag's first byte replaced with 0xCC (non-ASCII)."
expected_context = ["record_index", "byte_offset", "record_byte_offset"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e101_non_digit_start"
code = "E101"
variant = "DirectoryInvalid"
slug = "directory_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e101_directory_non_digit_start.bin"
description = "Directory entry 1 start-position byte 7 of 11 set to 'X' (first byte of the 5-byte start field)."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "field_tag"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e105_field_not_found"
code = "E105"
variant = "FieldNotFound"
slug = "field_not_found"
trigger_kind = "accessor"
trigger_fixture = "tests/data/simple_book.mrc"
description = "Parse simple_book.mrc cleanly, then call record.get_field_or_err('999')."
expected_context = ["field_tag"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e105_authority_field_not_found"
code = "E105"
variant = "FieldNotFound"
slug = "field_not_found"
trigger_kind = "accessor"
trigger_fixture = "tests/data/simple_authority.mrc"
description = "Parse simple_authority.mrc cleanly, then call record.get_field_or_err('999')."
expected_context = ["field_tag"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e105_holdings_field_not_found"
code = "E105"
variant = "FieldNotFound"
slug = "field_not_found"
trigger_kind = "accessor"
trigger_fixture = "tests/data/simple_holdings.mrc"
description = "Parse simple_holdings.mrc cleanly, then call record.get_field_or_err('999')."
expected_context = ["field_tag"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e106_field_length_past_data"
code = "E106"
variant = "InvalidField"
slug = "invalid_field"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e106_field_length_past_data.bin"
description = "Directory entry for tag 100 claims length '9999' (was '0025'); declared field bytes extend past the data area."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "field_tag"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e106_expected_subfield_delimiter"
code = "E106"
variant = "InvalidField"
slug = "invalid_field"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e106_expected_subfield_delimiter.bin"
description = "Byte 63 (first subfield delimiter 0x1F of the 100 field) replaced with 'X'."
expected_context = ["record_index", "byte_offset", "record_byte_offset", "field_tag"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e106_authority_field_too_short"
code = "E106"
variant = "InvalidField"
slug = "invalid_field"
trigger_kind = "parse_authority"
trigger_fixture = "tests/data/error_fixtures/e106_authority_field_too_short.bin"
description = "Authority record's 100 data-field directory length set to '0001' (1 byte; below the 2-byte indicator minimum)."
expected_context = ["record_index", "byte_offset", "field_tag"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e106_recovery_invalid_field"
code = "E106"
variant = "InvalidField"
slug = "invalid_field"
trigger_kind = "parse_iso2709_lenient"
trigger_fixture = "tests/data/error_fixtures/e106_recovery_invalid_field.bin"
description = "Leader claims 999-byte record; only the directory (with a non-digit length field 'ABCD') is provided. Truncation routes through try_recover_record, which calls parse_4digits and pushes InvalidField."
expected_context = []
recovery_modes = ["lenient"]
wired = true
[[case]]
id = "e201_bad_indicator_245"
code = "E201"
variant = "InvalidIndicator"
slug = "invalid_indicator"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e201_bad_indicator.bin"
description = "First indicator byte of field 245 is ':' (not digit/space)."
expected_context = [
"record_index",
"byte_offset",
"record_byte_offset",
"field_tag",
"indicator_position",
"found",
"expected",
]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e201_per_tag_indicator_245"
code = "E201"
variant = "InvalidIndicator"
slug = "invalid_indicator"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e201_per_tag_indicator_245.bin"
description = "First indicator of field 245 is '9' (byte-valid digit but per-tag rule allows only 0/1)."
expected_context = [
"record_index",
"byte_offset",
"record_byte_offset",
"field_tag",
"indicator_position",
"found",
"expected",
]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e202_non_printable_subfield_code"
code = "E202"
variant = "BadSubfieldCode"
slug = "bad_subfield_code"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e202_non_printable_subfield_code.bin"
description = "Byte 64 (subfield code 'a' after 0x1F at byte 63) replaced with 0x00."
expected_context = [
"record_index",
"byte_offset",
"record_byte_offset",
"field_tag",
"subfield_code",
]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e301_invalid_utf8_in_subfield"
code = "E301"
variant = "EncodingError"
slug = "utf8_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e301_invalid_utf8_in_subfield.bin"
description = "Byte 70 (inside the 100$a 'Fitzgerald' subfield value) replaced with 0xFF."
expected_context = ["record_index"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e301_invalid_utf8_in_control_field"
code = "E301"
variant = "EncodingError"
slug = "utf8_invalid"
trigger_kind = "parse_iso2709"
trigger_fixture = "tests/data/error_fixtures/e301_invalid_utf8_in_control_field.bin"
description = "Byte 49 (first byte of 008 control field in with_control_fields.mrc) replaced with 0xFF."
expected_context = ["record_index"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e301_invalid_utf8_in_authority_control_field"
code = "E301"
variant = "EncodingError"
slug = "utf8_invalid"
trigger_kind = "parse_authority"
trigger_fixture = "tests/data/error_fixtures/e301_invalid_utf8_in_authority_control_field.bin"
description = "Byte 73 (first byte of first control field in simple_authority.mrc) replaced with 0xFF; leader position 18 set to ' ' so the MARC 21 Authority Format allowed-value sets accept the leader at strict_marc."
expected_context = ["record_index"]
recovery_modes = ["strict"]
validation_level = "strict_marc"
wired = true
[[case]]
id = "e401_marcxml_close_tag_mismatch"
code = "E401"
variant = "XmlError"
slug = "marcxml_invalid"
trigger_kind = "parse_marcxml"
trigger_fixture = "tests/data/error_fixtures/e401_malformed_marcxml.xml"
description = "Subfield 'a' closing tag is </WRONG> instead of </subfield>."
expected_context = []
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e401_no_record_element"
code = "E401"
variant = "XmlError"
slug = "marcxml_invalid"
trigger_kind = "parse_marcxml"
trigger_fixture = "tests/data/error_fixtures/e401_no_record_element.xml"
description = "Well-formed XML wrapper with no <record> element inside."
expected_context = []
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e401_bad_char_reference"
code = "E401"
variant = "XmlError"
slug = "marcxml_invalid"
trigger_kind = "parse_marcxml"
trigger_fixture = "tests/data/error_fixtures/e401_bad_char_reference.xml"
description = "Subfield 'a' text contains � (overflowing character reference)."
expected_context = []
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e401_unexpected_eof_in_subfield"
code = "E401"
variant = "XmlError"
slug = "marcxml_invalid"
trigger_kind = "parse_marcxml"
trigger_fixture = "tests/data/error_fixtures/e401_unexpected_eof_in_subfield.xml"
description = "XML truncated mid-text inside <subfield>; no closing tag."
expected_context = []
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e402_marcjson_truncated"
code = "E402"
variant = "JsonError"
slug = "marcjson_invalid"
trigger_kind = "parse_marcjson"
trigger_fixture = "tests/data/error_fixtures/e402_malformed_marcjson.json"
description = "JSON document is truncated mid-string in a subfield value."
expected_context = []
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e404_record_too_large_for_iso2709"
code = "E404"
variant = "WriterError"
slug = "record_too_large_for_iso2709"
trigger_kind = "writer"
description = "Construct a record whose total length or base address exceeds 99999 and attempt to serialize it."
expected_context = ["record_index"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e404_writer_non_ascii_tag"
code = "E404"
variant = "WriterError"
slug = "record_too_large_for_iso2709"
trigger_kind = "writer"
description = "Construct a record with a field whose tag is not 3 ASCII bytes and attempt to serialize it."
expected_context = ["record_index"]
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e404_writer_finished_writer_reuse"
code = "E404"
variant = "WriterError"
slug = "record_too_large_for_iso2709"
trigger_kind = "writer"
description = "Call MarcWriter::finish(), then attempt another write_record on the same writer."
expected_context = []
recovery_modes = ["strict"]
wired = true
[[case]]
id = "e404_check_iso2709_size_base_address_overflow_programmatic"
code = "E404"
variant = "WriterError"
slug = "record_too_large_for_iso2709"
trigger_kind = "programmatic_writer_check"
description = "Call iso2709::check_iso2709_size(record_length=1, base_address=100_000) directly to exercise the base_address > 99999 defensive branch."
expected_context = ["record_index"]
recovery_modes = ["strict"]
wired = true