Skip to content

Return errors instead of panicking in fallible functions - #10755

Draft
emilk wants to merge 1 commit into
apache:mainfrom
emilk:emilk/missing-panics-doc
Draft

Return errors instead of panicking in fallible functions#10755
emilk wants to merge 1 commit into
apache:mainfrom
emilk:emilk/missing-panics-doc

Conversation

@emilk

@emilk emilk commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

While clearing clippy::missing_panics_doc, a pattern turned up: functions that
already return Result, but report some failures by panicking. Several are
reachable from untrusted input, so the panic is a denial of service rather than a
bug report.

Documenting those panics would normalise them, so this returns errors instead.

This is one of four PRs splitting up the work. Each one stands on its own and
touches its own set of functions, but they are meant to land in order, since the
later ones assume the earlier ones:

  1. this PR - return errors from fallible functions
  2. Remove some unwraps #10759 - remove unreachable panics
  3. Document the panics of public functions #10760 - document the panics that genuinely remain
  4. Mark unreachable panics with #[expect(clippy::missing_panics_doc)] #10761 - #[expect] the unreachable ones, so the lint can be turned on

What changes are included in this PR?

Only functions that could report the failure and did not. Highlights:

  • read_record_batch asserted on the variadic buffer counts declared by the IPC
    message, and FileReaderBuilder::build unwrapped footer metadata whose key or
    value may be absent
  • b64_decode panicked on invalid base64 in the input array
  • FFI_ArrowSchema::metadata unwrapped producer-supplied lengths, and
    preallocated a HashMap for an entry count it had not checked
  • ArrayData::validate_values had unreachable!() arms, in a function whose
    whole job is to report bad data
  • concat_elements_bytes/concat_elements_utf8_many unwrapped the offset
    conversion, so a long enough concatenation panicked
  • ColumnReader::skip_records and get_row_group_column_bloom_filter unwrapped
    parquet metadata
  • the Flight SQL client unwrapped a truncated or unexpected server response

Are these changes tested?

Covered by the existing tests, plus new tests for the b64_decode and
ArrayData::validate_values error paths.

Are there any user-facing changes?

No API changes. Some calls that used to panic now return an Err, which is the
point of the PR.

Comment thread arrow-array/src/array/run_array.rs Outdated
///
/// # Panics
///
/// With the `force_validate` feature enabled, panics if `data_type`, `run_ends`

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if we should document this.

The force_validate feature has no docs in arrow-array/Cargo.toml nor in arrow-array/src/lib.rs, so I don't know what it is for.

@emilk
emilk marked this pull request as ready for review August 19, 2026 13:34
@emilk
emilk marked this pull request as draft August 19, 2026 13:37
These functions already return `Result`, but reported some failures by
panicking. Several are reachable from untrusted input, where a panic is a
denial of service rather than a bug report:

* `b64_decode` panicked on invalid base64 in the input array
* `read_record_batch` asserted on the variadic buffer counts declared by the
  IPC message, and `FileReaderBuilder::build` unwrapped footer metadata whose
  key or value may be absent
* `Decoder::flush` (arrow-json) unwrapped a malformed tape
* `FFI_ArrowSchema::metadata` unwrapped lengths supplied by the producer, and
  preallocated a `HashMap` for an entry count it had not checked
* `ArrayData::validate_values` had `unreachable!()` arms for dictionary key
  and run end types, in a function whose whole job is to report bad data
* `concat_elements_bytes` and `concat_elements_utf8_many` unwrapped the offset
  conversion, so a long enough concatenation panicked
* `ColumnReader::skip_records` asserted on a page's record count
* `get_row_group_column_bloom_filter` (sync and async) unwrapped the Bloom
  filter offsets, and subtracted them without checking
* `ArrowColumnWriter::close` and `SerializedFileWriter::next_row_group`
  unwrapped on shared state and on overflow
* the three `try_new_from_builder` dictionary builders unwrapped on a shared
  key buffer
* the Flight SQL client unwrapped a truncated or unexpected server response
* `garbage_collect_dictionary` unwrapped the new dictionary key
* `data_type_from_json`, `field_from_json`, `ArrowFile::read_batch(es)` and
  `open_json_file` unwrapped malformed JSON

Adds tests for the base64 and `validate_values` error paths.

The remaining panics are documented or removed separately; this covers only
the functions that could report the failure and did not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@emilk emilk changed the title Document or remove panics in public functions Return errors instead of panicking in fallible functions Aug 19, 2026

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @emilk -- this is pretty cool

keys_builder: new_keys
.into_builder()
.expect("underlying buffer has no references"),
keys_builder: new_keys.into_builder().map_err(|_| {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this actually happen? I think it is fine to make it a real error, but I think it would be good to mark the error if it isn't actually expected (like "Internal Error: source keys are ....")?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants