{
  "purpose": "Reproducible teaching fixtures for diagnosing why a Parquet file will not open",
  "generated_on": "2026-08-25",
  "generator": "scripts/generate_parquet_open_failure_fixtures.py",
  "native_duckdb_version": "v1.5.3",
  "pyarrow_version": "18.1.0",
  "control": {
    "rows": 5000,
    "event_id_sum": 12497500,
    "payload_length_sum": 2135000,
    "row_groups": 1,
    "footer_length_bytes": 1371,
    "footer_start_offset": 71099,
    "compression": "GZIP",
    "data_page_version": "2.0",
    "page_checksums": true
  },
  "corruption_recipe": {
    "fixture": "footer-valid-body-corrupt.parquet",
    "page_checksum_written": true,
    "payload_data_page_offset": 7037,
    "flipped_byte_offset": 7937,
    "original_byte_hex": "1f",
    "corrupted_byte_hex": "1e",
    "footer_start_offset": 71099,
    "footer_copied_intact": true
  },
  "encrypted_validation": {
    "fixture": "encrypted-footer.parquet",
    "rows_with_test_keys": 4,
    "round_trip_with_test_keys": true,
    "warning": "The generator's key wrapper and embedded test keys are deliberately insecure and must never be copied into production.",
    "byte_stability": "Encrypted bytes are nondeterministic because PyArrow generates random data keys and nonces; use the manifest hash for this generated copy."
  },
  "evidence_artifacts": [
    {
      "name": "generate_parquet_open_failure_fixtures.py",
      "role": "fixture_generator",
      "bytes": 17183,
      "sha256": "0eaf9daa94a05c42a00839a4d39dc3bd0d9a7e205a61bd8623dc7195af67f34d"
    }
  ],
  "limitations": [
    "Tiny synthetic teaching files; not a representative corruption or compatibility corpus",
    "Exact exception wording is specific to the recorded reader versions and can change",
    "The internal-corruption fixture flips one GZIP header byte and does not model every damaged page",
    "Boundary magic and a parseable footer do not prove that every data page decodes",
    "Encrypted output is semantically reproducible but not byte-stable because its data keys and nonces are random",
    "Remote authentication, CORS, range handling, and browser memory are documented separately and are not represented by these local files"
  ],
  "fixtures": [
    {
      "name": "valid-control.parquet",
      "role": "valid_checksummed_gzip_control",
      "bytes": 72478,
      "sha256": "3a3cc6591562bd909eb0384c77a4028b0a7d0ace1d4657e514cfe89d625748be",
      "first_16_bytes_hex": "50 41 52 31 15 06 15 c6 b8 02 15 f8 6c 15 8e d5",
      "last_16_bytes_hex": "2c 1c 00 00 1c 00 00 00 5b 05 00 00 50 41 52 31",
      "boundary_magic": {
        "first_four_ascii": "PAR1",
        "last_four_ascii": "PAR1"
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "ok",
          "columns": [
            "column_name",
            "column_type",
            "null",
            "key",
            "default",
            "extra"
          ],
          "rows": [
            [
              "event_id",
              "INTEGER",
              "YES",
              null,
              null,
              null
            ],
            [
              "payload",
              "VARCHAR",
              "YES",
              null,
              null,
              null
            ]
          ]
        },
        "metadata_count": {
          "status": "ok",
          "columns": [
            "rows"
          ],
          "rows": [
            [
              5000
            ]
          ]
        },
        "full_decode": {
          "status": "ok",
          "columns": [
            "decoded_check"
          ],
          "rows": [
            [
              2135000
            ]
          ]
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "ok",
          "rows": 5000,
          "row_groups": 1,
          "columns": [
            "event_id",
            "payload"
          ]
        },
        "full_decode_with_checksum_verification": {
          "status": "ok",
          "rows": 5000,
          "columns": [
            "event_id",
            "payload"
          ]
        }
      },
      "expected_viewparquet_entry": "accepted_then_opened"
    },
    {
      "name": "valid-control-no-extension",
      "role": "valid_control_without_extension",
      "bytes": 72478,
      "sha256": "3a3cc6591562bd909eb0384c77a4028b0a7d0ace1d4657e514cfe89d625748be",
      "first_16_bytes_hex": "50 41 52 31 15 06 15 c6 b8 02 15 f8 6c 15 8e d5",
      "last_16_bytes_hex": "2c 1c 00 00 1c 00 00 00 5b 05 00 00 50 41 52 31",
      "boundary_magic": {
        "first_four_ascii": "PAR1",
        "last_four_ascii": "PAR1"
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "ok",
          "columns": [
            "column_name",
            "column_type",
            "null",
            "key",
            "default",
            "extra"
          ],
          "rows": [
            [
              "event_id",
              "INTEGER",
              "YES",
              null,
              null,
              null
            ],
            [
              "payload",
              "VARCHAR",
              "YES",
              null,
              null,
              null
            ]
          ]
        },
        "metadata_count": {
          "status": "ok",
          "columns": [
            "rows"
          ],
          "rows": [
            [
              5000
            ]
          ]
        },
        "full_decode": {
          "status": "ok",
          "columns": [
            "decoded_check"
          ],
          "rows": [
            [
              2135000
            ]
          ]
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "ok",
          "rows": 5000,
          "row_groups": 1,
          "columns": [
            "event_id",
            "payload"
          ]
        },
        "full_decode_with_checksum_verification": {
          "status": "ok",
          "rows": 5000,
          "columns": [
            "event_id",
            "payload"
          ]
        }
      },
      "expected_viewparquet_entry": "rejected_before_duckdb_due_to_filename_extension"
    },
    {
      "name": "html-error-response.parquet",
      "role": "html_response_renamed_parquet",
      "bytes": 85,
      "sha256": "524c6d494aa95e0616c17b0bfb27541d5b1639c925aca5c20ff1ef551b4bc4fd",
      "first_16_bytes_hex": "3c 21 64 6f 63 74 79 70 65 20 68 74 6d 6c 3e 3c",
      "last_16_bytes_hex": "64 3c 2f 62 6f 64 79 3e 3c 2f 68 74 6d 6c 3e 0a",
      "boundary_magic": {
        "first_four_ascii": "<!do",
        "last_four_ascii": "ml>\n"
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'html-error-response.parquet'"
        },
        "metadata_count": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'html-error-response.parquet'"
        },
        "full_decode": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'html-error-response.parquet'"
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "error",
          "error": "Parquet magic bytes not found in footer. Either the file is corrupted or this is not a parquet file."
        },
        "full_decode_with_checksum_verification": {
          "status": "error",
          "error": "Error creating dataset. Could not read schema from 'html-error-response.parquet'. Is this a 'parquet' file?: Could not open Parquet input source 'html-error-response.parquet': Parquet magic bytes not found in footer. Either the file is corrupted or this is not a parquet file."
        }
      },
      "expected_viewparquet_entry": "accepted_by_extension_then_duckdb_error"
    },
    {
      "name": "git-lfs-pointer.parquet",
      "role": "git_lfs_pointer_renamed_parquet",
      "bytes": 130,
      "sha256": "e675ca4ebf6af04f53e6e165ff576831ac622974d2e97c9172c0c347ec873e7d",
      "first_16_bytes_hex": "76 65 72 73 69 6f 6e 20 68 74 74 70 73 3a 2f 2f",
      "last_16_bytes_hex": "30 30 30 30 0a 73 69 7a 65 20 32 34 35 37 36 0a",
      "boundary_magic": {
        "first_four_ascii": "vers",
        "last_four_ascii": "576\n"
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'git-lfs-pointer.parquet'"
        },
        "metadata_count": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'git-lfs-pointer.parquet'"
        },
        "full_decode": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'git-lfs-pointer.parquet'"
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "error",
          "error": "Parquet magic bytes not found in footer. Either the file is corrupted or this is not a parquet file."
        },
        "full_decode_with_checksum_verification": {
          "status": "error",
          "error": "Error creating dataset. Could not read schema from 'git-lfs-pointer.parquet'. Is this a 'parquet' file?: Could not open Parquet input source 'git-lfs-pointer.parquet': Parquet magic bytes not found in footer. Either the file is corrupted or this is not a parquet file."
        }
      },
      "expected_viewparquet_entry": "accepted_by_extension_then_duckdb_error"
    },
    {
      "name": "zero-byte.parquet",
      "role": "zero_byte_file",
      "bytes": 0,
      "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
      "first_16_bytes_hex": "",
      "last_16_bytes_hex": "",
      "boundary_magic": {
        "first_four_ascii": "",
        "last_four_ascii": ""
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "error",
          "error": "Invalid Input Error: File 'zero-byte.parquet' too small to be a Parquet file"
        },
        "metadata_count": {
          "status": "error",
          "error": "Invalid Input Error: File 'zero-byte.parquet' too small to be a Parquet file"
        },
        "full_decode": {
          "status": "error",
          "error": "Invalid Input Error: File 'zero-byte.parquet' too small to be a Parquet file"
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "error",
          "error": "Parquet file size is 0 bytes"
        },
        "full_decode_with_checksum_verification": {
          "status": "error",
          "error": "Error creating dataset. Could not read schema from 'zero-byte.parquet'. Is this a 'parquet' file?: Could not open Parquet input source 'zero-byte.parquet': Parquet file size is 0 bytes"
        }
      },
      "expected_viewparquet_entry": "accepted_by_extension_then_duckdb_error"
    },
    {
      "name": "truncated-footer.parquet",
      "role": "truncated_before_footer_length_and_magic",
      "bytes": 72470,
      "sha256": "93101cda28a62e774e33301b81e70dcccd0396f8586d0ec603073cf764740317",
      "first_16_bytes_hex": "50 41 52 31 15 06 15 c6 b8 02 15 f8 6c 15 8e d5",
      "last_16_bytes_hex": "20 31 38 2e 31 2e 30 19 2c 1c 00 00 1c 00 00 00",
      "boundary_magic": {
        "first_four_ascii": "PAR1",
        "last_four_ascii": "\u001c\u0000\u0000\u0000"
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'truncated-footer.parquet'"
        },
        "metadata_count": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'truncated-footer.parquet'"
        },
        "full_decode": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'truncated-footer.parquet'"
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "error",
          "error": "Parquet magic bytes not found in footer. Either the file is corrupted or this is not a parquet file."
        },
        "full_decode_with_checksum_verification": {
          "status": "error",
          "error": "Error creating dataset. Could not read schema from 'truncated-footer.parquet'. Is this a 'parquet' file?: Could not open Parquet input source 'truncated-footer.parquet': Parquet magic bytes not found in footer. Either the file is corrupted or this is not a parquet file."
        }
      },
      "expected_viewparquet_entry": "accepted_by_extension_then_duckdb_error"
    },
    {
      "name": "unclosed-writer.parquet",
      "role": "pyarrow_writer_bytes_copied_before_close",
      "bytes": 1120,
      "sha256": "4e37e56a6abdf33a9ba3b5ad80b2190219ffb389ad5b6621b5cb0a3ac0a8fc50",
      "first_16_bytes_hex": "50 41 52 31 15 04 15 80 04 15 80 04 4c 15 80 01",
      "last_16_bytes_hex": "ae 6c eb be 70 2c cf 74 6d df 78 ae ef 7c ef ff",
      "boundary_magic": {
        "first_four_ascii": "PAR1",
        "last_four_ascii": "\ufffd|\ufffd\ufffd"
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'unclosed-writer.parquet'"
        },
        "metadata_count": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'unclosed-writer.parquet'"
        },
        "full_decode": {
          "status": "error",
          "error": "Invalid Input Error: No magic bytes found at end of file 'unclosed-writer.parquet'"
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "error",
          "error": "Parquet magic bytes not found in footer. Either the file is corrupted or this is not a parquet file."
        },
        "full_decode_with_checksum_verification": {
          "status": "error",
          "error": "Error creating dataset. Could not read schema from 'unclosed-writer.parquet'. Is this a 'parquet' file?: Could not open Parquet input source 'unclosed-writer.parquet': Parquet magic bytes not found in footer. Either the file is corrupted or this is not a parquet file."
        }
      },
      "expected_viewparquet_entry": "accepted_by_extension_then_duckdb_error"
    },
    {
      "name": "footer-valid-body-corrupt.parquet",
      "role": "parseable_footer_with_one_damaged_checksummed_page",
      "bytes": 72478,
      "sha256": "85c92e9d5a3aeaaa0c50adfd8eba4b7e8c9d9ade70038e3aab7010681015af4e",
      "first_16_bytes_hex": "50 41 52 31 15 06 15 c6 b8 02 15 f8 6c 15 8e d5",
      "last_16_bytes_hex": "2c 1c 00 00 1c 00 00 00 5b 05 00 00 50 41 52 31",
      "boundary_magic": {
        "first_four_ascii": "PAR1",
        "last_four_ascii": "PAR1"
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "ok",
          "columns": [
            "column_name",
            "column_type",
            "null",
            "key",
            "default",
            "extra"
          ],
          "rows": [
            [
              "event_id",
              "INTEGER",
              "YES",
              null,
              null,
              null
            ],
            [
              "payload",
              "VARCHAR",
              "YES",
              null,
              null,
              null
            ]
          ]
        },
        "metadata_count": {
          "status": "ok",
          "columns": [
            "rows"
          ],
          "rows": [
            [
              5000
            ]
          ]
        },
        "full_decode": {
          "status": "error",
          "error": "Input is invalid/unsupported GZIP stream"
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "ok",
          "rows": 5000,
          "row_groups": 1,
          "columns": [
            "event_id",
            "payload"
          ]
        },
        "full_decode_with_checksum_verification": {
          "status": "error",
          "error": "could not verify page integrity, CRC checksum verification failed for page_ordinal 0"
        }
      },
      "expected_viewparquet_entry": "accepted_by_extension_then_decode_error"
    },
    {
      "name": "encrypted-footer.parquet",
      "role": "valid_encrypted_footer_requiring_keys",
      "bytes": 3133,
      "sha256": "904643baa5aebb6bd87f142145e6bbfc610694d8c3439ffc1ba3b8e801ff57c2",
      "first_16_bytes_hex": "50 41 52 45 2a 00 00 00 8d 74 a6 fd f3 62 d5 31",
      "last_16_bytes_hex": "1a 07 d3 71 20 d8 69 83 3c 09 00 00 50 41 52 45",
      "boundary_magic": {
        "first_four_ascii": "PARE",
        "last_four_ascii": "PARE"
      },
      "native_duckdb": {
        "footer_schema": {
          "status": "error",
          "error": "Invalid Input Error: File 'encrypted-footer.parquet' is encrypted, but 'encryption_config' was not set"
        },
        "metadata_count": {
          "status": "error",
          "error": "Invalid Input Error: File 'encrypted-footer.parquet' is encrypted, but 'encryption_config' was not set"
        },
        "full_decode": {
          "status": "error",
          "error": "Invalid Input Error: File 'encrypted-footer.parquet' is encrypted, but 'encryption_config' was not set"
        }
      },
      "pyarrow": {
        "footer_metadata": {
          "status": "error",
          "error": "Could not read encrypted metadata, no decryption found in reader's properties"
        },
        "full_decode_with_checksum_verification": {
          "status": "error",
          "error": "Error creating dataset. Could not read schema from 'encrypted-footer.parquet'. Is this a 'parquet' file?: Could not open Parquet input source 'encrypted-footer.parquet': Could not read encrypted metadata, no decryption found in reader's properties"
        }
      },
      "expected_viewparquet_entry": "accepted_by_extension_then_reader_requires_encryption_config"
    }
  ]
}
