---
title: "Validating inputs and handling errors"
description: "Understand checks for networks, paths, arrays, and path files, with small examples of common errors and corrections."
eyebrow: "API reference"
---

## Input and path checks {#layers}

A contraction first needs tensor connectivity, then a contraction order, and finally numerical arrays. ArcTN checks consistency at the corresponding stages. Incorrect dimensions, for example, make array shapes disagree with the network, while reusing a consumed tensor in a path makes later steps impossible.

### Network: complete indices and dimensions

`inputs` lists the indices on every input tensor axis, `output` lists the retained result indices, and `size_dict` gives each index dimension. The network is checked even for `arctn_path` calls that search without arrays:

- The network must contain at least one input tensor. Every used index needs a dimension in `size_dict`, with no unused entries.
- Dimensions must be positive integers. For example, `3` is valid; `0`, `-1`, `3.5`, and `True` are invalid.
- Indices in `output` must appear in the inputs and be unique. Their order is the result-axis order.
- The same index may appear in multiple input tensors; within one input tensor, at most two occurrences are currently allowed.

In the matrix multiplication from [Quick start](/docs/quick-start#network), `inputs` uses four indices: `"a"`, `"b"`, `"c"`, and `"d"`. Omitting `"b": 3` leaves the shared dimension of two connected matrices undefined, so restore it in `size_dict`. Setting `output` to `("a", "a")` repeats an index; for this example, restore `("a", "d")`.

### Path: valid successive steps

A contraction path states which two tensors to combine at each step. ArcTN checks that the IDs are different, that both tensors already exist and have not been consumed, and that exactly one result remains after all steps.

With three inputs, SSA input IDs are `0`, `1`, `2`, and the first result is `3`. Path `[(0, 1), (3, 2)]` contracts inputs `0` and `1`, then result `3` with input `2`. Path `[(0, 1), (0, 2)]` incorrectly reuses input `0` in the second step; change that step to `(3, 2)`. Keeping only the first step also leaves an incomplete path with two unmerged tensors.

SSA IDs are never reassigned. In contrast, an opt_einsum linear path uses positions in the current list of remaining tensors. `ArcTNExecutionPlan` stores an SSA path, which `plan.to_linear_path()` converts to a linear path.

### Arrays: matching counts, shapes, and data types

At execution, `arrays[i]` must correspond to `inputs[i]`, with axis sizes matching `size_dict`. The three quick-start arrays must have shapes `(2, 3)`, `(3, 4)`, `(4, 2)` in that order. Transposing the first to `(3, 2)` violates `inputs[0] = ("a", "b")`. Supply arrays in the required axis order, or, if the network really changed, update its definition and regenerate the path.

When executing with `arctn_contract`, `plan.execute()`, or `ArcTNCompiledContraction.execute()`, all arrays must share one supported data type: `float32`, `float64`, `complex64`, or `complex128`. Explicitly setting `dtype=np.float64` when creating NumPy examples avoids unsupported default integer arrays. Use a complex type for complex data to retain imaginary components. If only the ArcTN path or tree is passed to Quimb/Cotengra, the actual execution library checks array types.

## Catching parameter errors {#parameter-example}

Starting from [Quick start](/docs/quick-start#network), use its `inputs`, `output`, and `size_dict` and deliberately omit the `target_size` required by Dynamic slicing:

```python
from arctn import arctn_schedule

try:
    report = arctn_schedule(
        inputs, output, size_dict,
        slicing_mode="dynamic",
    )
except ValueError as exc:
    print(f"Invalid planning parameters or network: {exc}")
```

The exception explains that `slicing_mode="dynamic"` requires `target_size`. Add `target_size=4` to limit every generated tensor within each slice, including the final output, to 4 elements. This `4` is for the small example; choose a limit based on your network and available memory in real use.

Valid parameters may still raise `ValueError` if no slicing scheme satisfying `target_size` is found. Based on the error, consider raising the size limit, or increasing `max_time` if a time limit was set. Search never relaxes `target_size` automatically.

## Checking a saved path file {#plan-example}

Follow [Saving and reusing paths](/docs/tutorial-reuse#save-load) to save `plan.json`, then check it with the quick-start network definition and `arrays`:

```python
from arctn import ArcTNExecutionPlan, PlanValidationError

try:
    plan = ArcTNExecutionPlan.load("plan.json")
    plan.validate(inputs, output, size_dict, arrays=arrays)
except PlanValidationError as exc:
    print(f"File, network, or array validation failed: {exc}")
else:
    result = plan.execute(arrays, backend="native")
```

`ArcTNExecutionPlan.load()` reads the file and checks consistency among the saved network, SSA path, sliced indices, and size limit. Core metrics stored in the file, such as FLOPs and intermediate sizes, are recomputed from the network and path and compared. Loading does not search for a new path.

Next, `plan.validate()` compares current connectivity, dimensions, and input/output order with the saved network and checks array count, shapes, and data types. `plan.validate(arrays=arrays)` can check arrays alone. If supplying a network definition as well, provide `inputs`, `output`, and `size_dict` together. Success returns `None`; failure raises an exception.

For example, if the saved network requires first-array shape `(2, 3)` but receives `(2, 4)`, the error reports actual and required shapes. Supply the correct array if it was a mix-up; if dimensions really changed, regenerate and save a path for the new network. Missing or unreadable files and malformed JSON are also wrapped by `load()` as `PlanValidationError`. Check the path from the error, or save the file again from the original network.

These checks validate network, path, and array information. To verify numerical results, reuse `np.testing.assert_allclose(result, a @ b @ c)` from Quick start to compare with a known reference calculation.

## Time limits {#deadline}

`max_time` is in seconds and must be finite and positive. Search checks elapsed time during execution, so a call with `max_time=1.0` may return after more than 1 second. A successful return still provides a complete executable path. If the entire process must stop at a strict deadline, enforce it outside the caller, for example with a job-scheduler time limit.

## Common exceptions {#errors}

| Exception | Common cause and response |
| --- | --- |
| `TypeError` | Incorrect parameter type, such as `target_size=4.0`; pass integer `4` instead. |
| `ValueError` | Invalid network, path, or weights, or no scheme satisfying the constraint; inspect the indicated parameter. |
| `PlanValidationError` | Path-file loading or file/network/array validation failed. It subclasses `ValueError` and can be caught separately. |
| `NotImplementedError` | Passing `memory_limit` or requesting slicing through path-only `ArcTNOptimizer.__call__`; use `arctn_tree` or `arctn_contract` with `target_size` to retain slicing information. |
| `ImportError` | Missing optional dependencies such as Cotengra or opt_einsum; install those required by the feature using [Installation](/docs/installation#python). |
| `OverflowError` | An integer exceeds the range representable on this platform; check its value and units and use the supported range. |

High-level Rust interfaces usually return success or error through `Result`; propagate errors to callers with `?`. See the [Rust API](/docs/rust-api) for return types.
