Skip to content
heliaAOT
Guides
HELIA HUB

Troubleshooting

Start with the failing stage and preserve its message, configuration and model identity. Typed conversion failures raise a HeliaAotError subclass that may include an actionable hint; a golden-data archive the loader cannot parse is one of them, a GoldenDataError. Unexpected exceptions retain their traceback. A traceback alone does not tell you whether the model, configuration or compiler is at fault.

Symptom Check Next action
Configuration fails before conversion Field names, enum values and the validation message Compare the setting with the Configuration reference.
A placement rule has no effect Tensor kind spelling, actual tensor id and rule precedence Use constant, persistent or scratch (in any case); specify both type and id to override a type rule.
The model uses operators heliaAOT does not support The UnsupportedModelError message, which lists each operator type with its node count and first node Check the operator catalog; re-export without those operators, or register them as custom operators from the Python API.
A platform field is ignored Whether platform.name is registered Use memory constraints for this model’s budget, or define a complete custom target under an unregistered name.
No kernel applies The node’s dtype, shape, options and target capabilities Check operator restrictions; precision is determined by model tensors.
Golden archive cannot load Path relative to the process, numeric arrays, required input_N/output_N keys, and each array’s element count and dtype Regenerate or correct the archive; keep verification enabled when claiming numerical agreement.
model_run returns 14 Successful model_init for the context Check initialization’s return value; calling context_init alone is insufficient.
model_run returns 200 Staged constants and hydration latch Complete hydration and mark it at the helper’s call point during initialization.
Outputs mismatch Input bytes, initial state, iteration count, golden source and tolerance units Reproduce the first mismatch and inspect those contracts before changing a tolerance.

If the message remains unexplained, report the full traceback, package version, target, resolved configuration and the smallest model or node description that reproduces it. Include whether failure occurred during conversion, build, initialization or inference.

A typed failure prints an Error: line and its hint, and exits with the code its class declares: 2 when your input is rejected (the command line, the configuration, a file it names such as the model, the golden data or the output location, the model type or format, or the target), whether before or during conversion, and 1 when a valid request fails while converting. The Errors reference lists each class’s code, the same exit_code the error carries in Python, and the command line reference lists every code.

A configuration that fails validation prints error: 1 validation error while parsing arguments (with the count of errors) and one line per error, with no separate hint line, and an invalid flag value prints the command line’s usage error; both exit 2.

Every class below also inherits the matching standard-library exception, so code already catching ValueError or OSError keeps working. The class list, with the base types, exit codes and docstrings as the code declares them, is in the Errors reference.

The base class for typed conversion failures. Catch it to handle that family. Seeing it raised directly, rather than one of its subclasses, is unusual.

A configuration value is invalid for the requested conversion. Also a ValueError.

Read the hint: it names the setting. ConfigValueError is what an operator raises when no kernel applies to a node, with exit_code 1, in which case the hint asks you to check that node’s dtype, shape and options against what a kernel supports: the operator catalog is the list. A configuration rejected on its own or against the target raises the subclass InvalidConfigError, so except ConfigValueError catches both.

The configuration is rejected on its own or against the target. A ConfigValueError, and its exit_code is 2.

Read the hint: it names the setting. An unknown configuration key is one: the message names the key, where it appeared and, when one is close, the nearest valid key. From Python, ConvertArgs.from_yaml raises it directly, and construction or model_validate raises it inside a pydantic ValidationError. A removed key or value is one too, and its hint names the replacement. convert() raises it directly for an unknown platform, an unknown memory.planner_options or transforms[].options key, a transform option value its type rejects, an unknown transform name or a transform listed more than once, an operators[] attribute key or value no operator the rule reaches takes, and a memory constraint or pin the target cannot honour.

A tensor read as quantized that carries no scale or no zero point raises a ConfigValueError, and the command line exits 1. The message names the operator that reads the tensor. Re-export the model with full-integer quantization, so every int8, uint8 and int16 tensor an operator reads carries a scale and a zero point; the hint says the same.

The input model could not be found or read. Also an OSError, but not a FileNotFoundError, since a damaged model is not a missing one. The CLI exits 2.

It is raised for a missing file, for a file without read permission, for a directory or a git-lfs pointer in place of the model, and for a file that cannot be decoded as a LiteRT flatbuffer or holds no subgraphs: empty, truncated or another format. Check model.path, run git lfs pull for a pointer, and re-export a damaged file. A file that decodes but is damaged inside can still fail later, possibly with an untyped exception and traceback. An out-of-range model.subgraph, an unknown model.type or an unsupported file extension is an InvalidConfigError instead.

The model uses a structure or a dtype heliaAOT cannot lower. Also a ConfigValueError, and so a ValueError: a handler for ConfigValueError catches it, and keeps catching an operator rejection that a later release raises as this narrower class.

The graph was recognized, so the message names the construct and the hint states the supported form. Read the hint before changing anything: the fix is usually in how the model was exported, not in the conversion. A recurrent loop whose weights are dequantized inside the loop body, for instance, is a weight-only FP16 export rather than a native FP16 model; see Precision.

Operators heliaAOT does not support. Raised before any operator is parsed, listing every operator type in the model that has no lowering, with its node count and first node index. Check the operator catalog, then re-export the model without those operators or, from the Python API, register them as custom operators. An operator code the LiteRT schema does not name is listed as UNKNOWN(<code>).

Unresolved dynamic tensor shapes after propagation. Raised as an UnsupportedModelError while propagating tensor shapes, in the command line’s Analyze group, when a tensor’s LiteRT shape_signature holds a negative dimension that shape propagation could neither resolve from the concrete input shapes nor confirm. The message lists the tensors by their LiteRT indices in the subgraph, written as strings, so 0 is the first tensor. A dynamic batch dimension on the model input resolves on its own, and shape-building subgraphs rooted at SHAPE are evaluated together with shapes during propagation. The usual cause is a shape that depends on a runtime value. Fix the export so the shape is concrete; the hint says the same. Run with --verbose 2 to see, per tensor, the signature and the shape propagation reached.

An output path already exists and --force was not given. Also a FileExistsError. The CLI exits 2.

Pass --force to overwrite, or point module.path somewhere else. The same error guards the residency report. A module.path that names a file, a .zip or .pack path that names a directory, a symbolic link to nothing, a module directory (module.name under module.path) that is a symbolic link, which is neither written through nor replaced, a location without write or search permission, or a file name too long for the file system is an InvalidConfigError instead, also exit 2, raised before the model loads where it can be. On Windows the write-permission check sees only a read-only attribute, so a location you cannot write may still fail when the module is exported.

An explicitly supplied golden-data archive could not be found. Also a FileNotFoundError, so existing Python callers can catch that standard type.

The CLI prints the error and its hint, then exits with code 2 without a traceback, as for any other rejected golden data. Set test.golden_data (or --test.golden-data) to an existing, readable .npz file, or regenerate the archive at that path. Keep numerical verification enabled when claiming agreement with the reference.

A supplied golden-data archive is missing a required tensor key. Also a KeyError.

Regenerate the archive with an input_N and an output_N entry for every model input and output, which is what the hint asks for. The CLI exits 2.

A supplied golden-data archive cannot be read, is not a readable .npz, or has an array without its tensor’s element count and dtype. Also a ValueError.

The CLI exits 2. For a file it cannot open, such as one without read permission, check the path and permissions. For a mismatch, the message names the key, the tensor and both shapes and dtypes. Save the archive with numpy.savez, one array per input_N and output_N key, each holding its tensor’s element count in its tensor’s dtype.

Automatic reference setup, execution or worker communication failures raise this error (also a RuntimeError), and the CLI exits 1. This does not attribute the failure to invalid user input. Available remote tracebacks are printed. The diagnostic identifies the model and phase. Supply test.golden_data (or --test.golden-data) from an independent reference when the backend cannot execute the model; use skip_verification only when output verification is intentionally omitted. Unexpected worker Python failures retain their remote traceback.

An operator reads a tensor that a later operator produces. Also a RuntimeError.

The message names the stage (the loaded model or a graph transform), the operator, the tensor and its producer. After a custom transform, fix or disable that transform. After a built-in transform it is a heliaAOT defect; please report it. In the loaded model, re-export the model with the LiteRT converter.

A codegen template referenced context its handler did not supply. Also a RuntimeError.

This is a heliaAOT defect, not a problem with your model, and the hint says so. The error names the operator and, where it can, the template and the line. It is reachable from a valid model, so please report it with the model or a description of the failing node.

An operator id is not one the generated C can use. Also a ValueError.

Code generation names each operator’s C functions and source file by its id, so an id must be the importer’s form: a decimal integer from 0 to 2147483647 without leading zeros, used by no other operator. The importer numbers operators that way, so the id comes from a custom parser or transform: give each operator it creates or renames a unique numeric id. The message names every operator whose id breaks the rule. The CLI exits 1.

A frozen registry, or a context that does not allow overrides, was changed. Also a RuntimeError.

Register custom parsers, operators and transforms in a customizer passed to build_default_registry_context, which runs before the context is frozen. To replace or remove a built-in entry there, pass allow_override=True.

A registry, or the platform registry, already holds the key. Also a KeyError.

Pass overwrite=True to Registry.register to replace the item, or use another key. Platform names must be unique in any case, so register a custom platform under a name no registered platform uses.

Warnings can explain why a setting did not take effect. Read them before trusting the resolved configuration or resulting plan.

Ignored platform fields. For a registered target, configured cpu, speeds, capabilities, preferred_memory_order and min_alignment do not override the registration. The converter warns and uses the registered definition. memories is the exception: the sizes it names replace the target’s for that conversion. See Choosing a target.

Some problems do not raise.

A rule that did not apply. The rule matched nothing, or a higher-priority rule overrode it. Id-only rules outrank type-only rules; later position decides only between equally specific rules. A rule that other rules override on every operator or tensor it matches logs a warning naming the rules that win. Types match in any case; ids match exactly. The resolved attributes are not printed at any verbosity: check the operator’s header for <PREFIX>_PUT_CODE_IN_ITCM, the plan’s fixed choices, and the residency report for tensor placement and ids. See precedence.

A module that compiles but does not match the reference. Compiling is not validation. Enable test.enabled, keep skip_verification: false and choose trusted golden outputs or the host-interpreter oracle. The generated test then checks agreement within test.tolerance; see the oracle and tolerance limits.

model_run returning 14 or 200. Status 14 means model initialization has not completed successfully; context_init alone does not enable a run. Status 200 means staged constants are not marked hydrated after a successful initialization. A replacement hydrate helper must finish populating the arenas and call the mark-hydrated function before returning success, because operator init hooks may immediately read those constants. Marking before model_init is ineffective: its context_init call clears the latch. See the hydration contract.

A build that will not link or compile. Check the ns-cmsis-nn version floor the generated header enforces, and the float switches the module requires. See Precision.