Skip to content

Improve error messages in uxarray/core - #1678

Open
Sevans711 wants to merge 4 commits into
mainfrom
sevans/error-messages-core
Open

Improve error messages in uxarray/core#1678
Sevans711 wants to merge 4 commits into
mainfrom
sevans/error-messages-core

Conversation

@Sevans711

@Sevans711 Sevans711 commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Closes #1677 (sub-issue of #1617)

Overview

Makes error messages clearer and more informative throughout uxarray/core. As suggested by #1617 this is attempting to be an exhaustive fix for all desired error message improvements in uxarray/core, while touching nothing outside of uxarray/core.

Tiny expansion of scope: fixes confusing/misleading error types in a few places missed by #1622:

  1. ValueError → TypeError in open_dataset() error related to either passing the wrong number of input args or using the wrong types of objects for inputs. TypeError is more appropriate than ValueError in both of those cases.
  2. ValueError → TypeError in UxDataArray.zonal_mean() errors raised when not isinstance(lat, (tuple, float, int, list, np.ndarray)) or when not isinstance(lat, (tuple, list, np.ndarray)).
  3. ValueError → TypeError in UxDataArray.from_healpix() error raised when not isinstance(da, xr.DataArray).

Aside from this tiny expansion of scope there should be no functionality changes; the only differences in this PR are the changes to error message contents.

Additional notes:

  • Test suite updates to error message string matching is a good spot-check that these changes are working; the tests failed until I updated the test suite to match the new strings.
  • Intentionally did not touch error messages in concat() because fixing bugs there might lead to needing different kinds of messages anyway (see uxarray.concat implementation incomplete/buggy and needs a docstring #1642).
  • Ran benchmarks to make sure there isn't any performance hit. (Highly unlikely, but could happen if errors are used as part of control flow in a hot loop and any objects now placed into error message strings take non-negligible time to convert to string.) (Removed run-benchmarks label after seeing there is no performance hit.)

PR Checklist

General

  • An issue is created and linked
  • Added appropriate labels (if your uxarray repo permissions allow it)
  • Filled out Overview and Expected Usage (if applicable) sections

Testing & Benchmarking

  • [N/A] Adequate tests are created if there is new functionality
  • Tests are not too basic (such as simply calling a function and nothing else)
  • [N/A] Tests cover all major paths in your new functions
  • If this PR could affect performance, ran ASV benchmarks and confirmed they show expected behavior (add a new benchmark if necessary)

AI Disclosure

AI Usage: GitHub Copilot's inline code suggestions, some tiny chats with Claude about error message style.

  • I take responsibility for all AI-generated content in my PR.
  • I have tested all AI-generated content in my PR.

@Sevans711 Sevans711 added documentation Improvements or additions to documentation improvement Improvements on existing features or infrastructure run-benchmark Run ASV benchmark workflow developer experience Makes the codebase easier to read, debug, maintain, or extend. design Design of an API, feature, or user interface (not just implementation details) labels Aug 17, 2026
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have stayed the same:

Change Before [efc469d] After [7a15584] Ratio Benchmark (Parameter)
201±1ms 202±0.9ms 1.00 bench_connectivity.Connectivity.time_edge_face('120km')
12.4±0.2ms 12.4±0.1ms 1.00 bench_connectivity.Connectivity.time_edge_face('480km')
201±0.7ms 201±1ms 1.00 bench_connectivity.Connectivity.time_edge_node('120km')
11.1±0.1ms 11.2±0.05ms 1.00 bench_connectivity.Connectivity.time_edge_node('480km')
203±1ms 200±0.4ms 0.98 bench_connectivity.Connectivity.time_face_edge('120km')
11.6±0.03ms 11.7±0.1ms 1.01 bench_connectivity.Connectivity.time_face_edge('480km')
900±5ms 889±5ms 0.99 bench_connectivity.Connectivity.time_face_face('120km')
57.9±0.9ms 57.0±0.7ms 0.98 bench_connectivity.Connectivity.time_face_face('480km')
71.8±2μs 70.2±1μs 0.98 bench_connectivity.Connectivity.time_face_node('120km')
68.7±1μs 67.1±2μs 0.98 bench_connectivity.Connectivity.time_face_node('480km')
414±10μs 411±10μs 0.99 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
353±10μs 364±10μs 1.03 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
204±3ms 200±2ms 0.98 bench_connectivity.Connectivity.time_node_edge('120km')
11.6±0.1ms 11.6±0.1ms 1.00 bench_connectivity.Connectivity.time_node_edge('480km')
86.4±1ms 88.9±4ms 1.03 bench_connectivity.Connectivity.time_node_face('120km')
5.35±0.05ms 5.29±0.03ms 0.99 bench_connectivity.Connectivity.time_node_face('480km')
8.86±0.1ms 8.87±0.09ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.84±0.05ms 2.79±0.05ms 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
10.5±10s 10.4±10ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
2.27±0.02ms 2.22±0.06ms 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
57.3k 57.3k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
12.3k 12.3k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
123k 123k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
128 128 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.27M 1.27M 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
50.1k 50.1k 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
1.48M 1.48M 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
712 712 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.98M 1.98M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
1.99M 1.99M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.15M 2.15M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
38.3k 38.3k 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
336M 336M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
365M 367M 1.01 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
337M 338M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
336M 337M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.25±0.03μs 1.22±0.04μs 0.98 geometry_kernels.AccucrossKernels.time_accucross
2.76±0.02μs 2.82±0.04μs 1.02 geometry_kernels.AccucrossKernels.time_accucross_pair
466±20ns 446±20ns 0.96 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
461±20ns 426±5ns 0.92 geometry_kernels.EFTPrimitives.time_diff_of_products
406±20ns 401±20ns 0.99 geometry_kernels.EFTPrimitives.time_two_prod
385±10ns 401±9ns 1.04 geometry_kernels.EFTPrimitives.time_two_sum
1.61±0.08μs 1.54±0.05μs 0.96 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
1.16±0.03μs 1.15±0.03μs 0.99 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
1.94±0.05μs 1.96±0.03μs 1.01 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
1.71±0.03μs 1.72±0.04μs 1.01 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
1.37±0.03μs 1.40±0.02μs 1.03 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
2.18±0.04μs 2.21±0.04μs 1.02 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
55.9±3μs 53.2±0.6μs 0.95 geometry_kernels.OrientPredicates.time_on_minor_arc
1.16±0.06μs 1.13±0.02μs 0.97 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
2.72±0.1ms 2.61±0.01ms 0.96 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.17±0ms 1.17±0ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.72±0.01ms 1.72±0.01ms 1.00 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
150±4μs 147±0.8μs 0.98 geometry_samebody.SameBodyConstLat.time_fp64_kernel
32.5±0.08ms 32.2±0.03ms 0.99 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
10.2±0.01ms 10.3±0ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
26.5±0.02ms 26.5±0.02ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
4.85±0.01ms 5.07±0.03ms 1.05 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
837±7ms 826±10ms 0.99 import.Imports.timeraw_import_uxarray
293M 293M 1.00 import.Imports.track_peakmem_import_uxarray
2.79±0.02ms 2.88±0.03ms 1.03 mpas_ocean.CheckNorm.time_check_norm('120km')
2.25±0.02ms 2.30±0.03ms 1.02 mpas_ocean.CheckNorm.time_check_norm('480km')
853±10ms 852±8ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
54.9±0.6ms 55.1±0.6ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
690±20μs 693±10μs 1.00 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
609±10μs 606±20μs 0.99 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.46±0.01ms 5.46±0.06ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
4.01±0.02ms 4.02±0.04ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
3.43±0s 3.47±0.04s 1.01 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
224±0.8ms 221±0.9ms 0.99 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.2±0.05ms 18.2±0.02ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
1.05±0.02ms 1.06±0.01ms 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.6±0.03ms 10.6±0.04ms 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
747±10μs 743±5μs 0.99 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
721±6ms 724±2ms 1.00 mpas_ocean.CrossSections.time_const_lat('120km', 1)
365±8ms 365±1ms 1.00 mpas_ocean.CrossSections.time_const_lat('120km', 2)
188±2ms 188±1ms 1.00 mpas_ocean.CrossSections.time_const_lat('120km', 4)
552±4ms 559±2ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 1)
281±1ms 282±1ms 1.00 mpas_ocean.CrossSections.time_const_lat('480km', 2)
146±2ms 145±1ms 1.00 mpas_ocean.CrossSections.time_const_lat('480km', 4)
26.3±0.2ms 25.1±0.09ms 0.96 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
3.56±0.1ms 3.61±0.08ms 1.02 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
62.9±0.6ms 62.1±8ms 0.99 mpas_ocean.FaceAreas.time_face_areas('120km')
4.88±5s 8.23±5ms ~0.00 mpas_ocean.FaceAreas.time_face_areas('480km')
229k 229k 1.00 mpas_ocean.FaceAreas.track_nbytes_face_areas('120km')
14.3k 14.3k 1.00 mpas_ocean.FaceAreas.track_nbytes_face_areas('480km')
2.12M 2.12M 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('120km')
823k 823k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
961±3ms 942±9ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
53.0±0.3ms 54.8±2ms 1.03 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
86.1±1ms 84.9±0.4ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.96±0.2ms 5.73±0.06ms 0.96 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
177±7ms 176±0.8ms 0.99 mpas_ocean.Gradient.time_gradient('120km')
12.5±0.05ms 12.3±0.2ms 0.99 mpas_ocean.Gradient.time_gradient('480km')
457k 457k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('120km')
28.7k 28.7k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('480km')
5.08M 5.08M 1.00 mpas_ocean.Gradient.track_peakmem_gradient('120km')
328k 328k 1.00 mpas_ocean.Gradient.track_peakmem_gradient('480km')
351M 352M 1.00 mpas_ocean.GradientColdStartRss.peakmem_gradient('120km')
331M 331M 1.00 mpas_ocean.GradientColdStartRss.peakmem_gradient('480km')
387±6μs 381±9μs 0.98 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
218±10μs 208±7μs 0.96 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
566±10μs 561±20μs 0.99 mpas_ocean.Integrate.time_integrate('120km')
513±20μs 500±20μs 0.98 mpas_ocean.Integrate.time_integrate('480km')
18.4M 18.4M 1.00 mpas_ocean.Integrate.track_nbytes_integrate('120km')
1.2M 1.2M 1.00 mpas_ocean.Integrate.track_nbytes_integrate('480km')
181±0.8ms 185±1ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
182±0.4ms 183±2ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
182±1ms 183±1ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.8±0.4ms 13.8±0.07ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.8±0.2ms 13.8±0.1ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.7±0.08ms 13.8±0.1ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
435±20μs 419±20μs 0.96 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
418±10μs 397±10μs 0.95 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
373±10μs 391±9μs 1.05 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
370±10μs 400±5μs 1.08 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
242±1ms 241±0.6ms 0.99 mpas_ocean.RemapDownsample.time_bilinear_remapping
294±7ms 294±3ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.9±0.08ms 15.7±0.1ms 0.99 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.42±0s 1.43±0.01s 1.01 mpas_ocean.RemapUpsample.time_bilinear_remapping
37.4±0.3ms 37.3±0.1ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
12.7±0.05ms 12.7±0.1ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
25.7±0.6ms 25.4±0.2ms 0.99 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.81±0.02ms 5.88±0.03ms 1.01 mpas_ocean.ZonalAverage.time_zonal_average('480km')
6.79±0.07ms 6.84±0.05ms 1.01 quad_hexagon.QuadHexagon.time_open_dataset
5.82±0.01ms 5.82±0.06ms 1.00 quad_hexagon.QuadHexagon.time_open_grid
408 408 1.00 quad_hexagon.QuadHexagon.track_nbytes_open_dataset
392 392 1.00 quad_hexagon.QuadHexagon.track_nbytes_open_grid
73.8k 73.8k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
73k 72.7k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_grid

@Sevans711 Sevans711 removed the run-benchmark Run ASV benchmark workflow label Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

design Design of an API, feature, or user interface (not just implementation details) developer experience Makes the codebase easier to read, debug, maintain, or extend. documentation Improvements or additions to documentation improvement Improvements on existing features or infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error messages improvements in uxarray/core

1 participant