Error handling#

The in-process API separates invalid input from native processing failures. Catch the narrowest exception that your application can handle correctly.

Exception hierarchy#

LaueError is the package base class.

ValueError, XML parse errors, OSError, and KeyError can also occur while loading geometry, crystal, or HDF5 input. See the relevant API reference for each loader.

Invalid input#

InputError reports invalid processing configuration, including:

  • Peak or indexing parameters outside supported ranges

  • An unknown detector identifier or inactive detector slot

  • A frame that is not a two-dimensional uint16 array

  • Invalid start, group, or depth

  • A frame region outside detector bounds

  • A mask shape that does not match the frame

  • An HDF5 detector identifier that does not match the selected geometry

Fix the input before retrying. The exception message names the failed check and includes the received value when useful.

import numpy as np

from lauelab.indexing import InputError

bad_frame = np.zeros((128, 128), dtype=np.float32)

try:
    indexer.index(bad_frame)
except InputError as error:
    print(error)

Memory failure#

A native stage raises MemoryError when it cannot allocate required storage. The message identifies the stage and includes its diagnostic.

Do not assume that immediate retry will succeed. Release unneeded arrays and results, reduce concurrent work, or move the workload to a process with sufficient memory before retrying.

Native indexing failure#

IndexingError reports numerical or internal failures in a native processing stage. Its message begins with the stage name, such as pixel-to-q conversion failed or orientation indexing failed.

Preserve the complete message. It can distinguish a geometry conversion problem from an orientation-indexing problem without exposing native status values as a public API.

No peaks or no patterns is not a failure and does not raise an exception. Apply a separate scientific acceptance policy to those results.

Reconstruction failure#

Reconstructor raises InputError and MemoryError for failures before the first stripe is processed. A failure after that point does not raise. It returns a ReconstructionResult with success=False, the message in error, and the progress made so far in last_completed_stripe. ReconstructionError names a native failure in that message; an I/O failure carries the underlying OSError text.

Check success on every result. reconstruct_points() applies the same rule to each point and continues the batch after a failed point. See Reconstruct a wire scan.

Batch strategy#

Use index_many() when the batch should stop on its first failure. Use an explicit loop when each frame needs an independent status:

from lauelab.indexing import IndexingError, InputError

results = {}
failures = {}

for frame_id, frame in frames.items():
    try:
        results[frame_id] = indexer.index(frame, keep_image=False)
    except (InputError, IndexingError) as error:
        failures[frame_id] = str(error)

Decide separately whether to catch MemoryError, OSError, and KeyError. Continuing after those failures may hide a system-wide resource problem or a repeated file-layout error.

Diagnostic context#

Record enough context to reproduce the call:

  • Package version or Git commit

  • Input identifier, shape, and dtype

  • Geometry and crystal identifiers

  • Detector slot and detector ID

  • start, group, and depth

  • Peak and indexing parameters

  • Mask identity or generation method

  • Exception type and complete message

Do not log full frame arrays. Remove user names, sample names, local paths, and other sensitive acquisition metadata before sharing a report.

Reflection simulation failures#

simulate_reflections() uses built-in exception types because its public result does not expose backend status:

  • TypeError reports unsupported package objects or numeric types.

  • ValueError reports invalid scientific inputs, including array shapes, non-finite values, atomless crystals, and invalid energy intervals.

  • RuntimeError reports private simulator loading, resource, execution, numerical, projection, or candidate-limit failures.

A valid simulation with no on-detector reflections returns an empty SimulationResult. It does not raise. The simulator has no fallback, so a RuntimeError never means that a simpler calculation replaced the requested one.

Detector-view preparation and rendering propagate these exceptions. Missing crystal context raises only when simulation_energy_range_kev is not None.