Skip to main content

onnx_runtime_loader/
error.rs

1use std::path::PathBuf;
2
3/// Errors produced while loading an ONNX model.
4#[derive(Debug, thiserror::Error)]
5pub enum LoaderError {
6    #[error(
7        "What: node {node} ({op_type}) carries opset version {node_version}, but the graph \
8         imports version {graph_version} for domain {domain:?}, and this model cannot be \
9         written out. \
10         Why: a per-node opset is an in-memory IR concept with no representation in ONNX's \
11         protobuf, so serialising would produce a model claiming the wrong operator version \
12         with nothing downstream able to detect it. \
13         How: serialise before the pass that introduced the node-local version, or run with \
14         that fusion disabled."
15    )]
16    NodeVersionNotRepresentable {
17        node: String,
18        op_type: String,
19        domain: String,
20        node_version: i64,
21        graph_version: u64,
22    },
23    #[error("failed to read model file {path}: {source}")]
24    Io {
25        path: PathBuf,
26        #[source]
27        source: std::io::Error,
28    },
29
30    #[error("failed to parse ONNX protobuf: {0}")]
31    ProtobufParse(String),
32
33    #[error("failed to parse ONNX protobuf TextFormat: {0}")]
34    TextProtoParse(String),
35
36    #[error("unsupported opset: domain={domain}, version={version}")]
37    UnsupportedOpset { domain: String, version: u64 },
38
39    #[error(
40        "illegal ONNX model: operator {domain}::{op_type} at node {node} uses domain \
41         '{domain}' but no corresponding opset_import is declared. RULES #1: the model must \
42         declare an opset_import for domain '{domain}'; if you built this graph \
43         programmatically, add it before loading; if this is a file, the model is \
44         malformed/invalid per the ONNX spec"
45    )]
46    MissingOpsetImport {
47        op_type: String,
48        node: String,
49        domain: String,
50    },
51
52    #[error(
53        "illegal ONNX Einsum at node {node}: {detail}. RULES #1: Einsum syntax, schema version, \
54         homogeneous dtype, rank, diagonal, and broadcast constraints must be valid at model \
55         load. Expected: fix the equation/input metadata or export with the applicable ai.onnx \
56         opset (Einsum-12 for opsets 12..27; Einsum-28 for opset 28+)"
57    )]
58    InvalidEinsum { node: String, detail: String },
59
60    #[error(
61        "unsupported ONNX model: operator {domain}::{op_type} at node {node} carries a \
62         subgraph attribute '{attr}' (control-flow / nested-graph op) that this runtime cannot \
63         execute. RULES #1: ep-cpu recursively executes the standard control-flow ops \
64         If/Loop/Scan (ai.onnx), but not {op_type}, so the model cannot be run as-is. \
65         Expected: express control flow with If/Loop/Scan, lower/unroll {op_type} into \
66         supported ops, or register a kernel able to execute its subgraph body"
67    )]
68    UnsupportedControlFlow {
69        op_type: String,
70        node: String,
71        domain: String,
72        attr: String,
73    },
74
75    #[error(
76        "illegal ONNX model: operator {domain}::{op_type} at node {node} consumes tensor \
77         '{tensor}', but no producer exists — it is not a graph input, not an initializer, and \
78         not produced by any upstream node. RULES #1: every consumed tensor must be sourced; \
79         the graph is structurally malformed. Expected: add '{tensor}' as a graph input or \
80         initializer, or add a node that produces it; if this is a file, the model is invalid \
81         per the ONNX spec"
82    )]
83    DanglingTensorRef {
84        op_type: String,
85        node: String,
86        domain: String,
87        tensor: String,
88    },
89
90    #[error(
91        "illegal ONNX model: tensor '{tensor}' is declared as an initializer but is also \
92         produced as an output of node {node} — an initializer must be a constant source with \
93         no producer. RULES #1: initializer names must be unique and must not collide with any \
94         node output name; a producer-backed initializer would let a kernel write through \
95         read-only weight storage. Expected: rename the node output or the initializer so they \
96         no longer share a name; if this is a file, the model is malformed per the ONNX spec"
97    )]
98    InitializerHasProducer { tensor: String, node: String },
99
100    #[error(
101        "illegal ONNX model: value '{tensor}' has multiple producers ({first} and {second}). \
102         RULES #1: ONNX graphs are in SSA form, so a value name may be assigned only once. \
103         Expected: give each graph input and node output a unique name"
104    )]
105    DuplicateValueProducer {
106        tensor: String,
107        first: String,
108        second: String,
109    },
110
111    #[error(
112        "illegal ONNX model: operator {domain}::{op_type} at node {node} has attribute \
113         '{attr}' referring to function attribute '{ref_attr_name}' outside a FunctionProto. \
114         RULES #1: ref_attr_name is only bound while inlining a FunctionProto; it has no \
115         executable value in a main graph or control-flow subgraph. Expected: replace it with \
116         a concrete attribute value or move the node into a FunctionProto"
117    )]
118    RefAttributeOutsideFunction {
119        op_type: String,
120        node: String,
121        domain: String,
122        attr: String,
123        ref_attr_name: String,
124    },
125
126    #[error(
127        "illegal ONNX model: ir_version {ir_version} is invalid. RULES #1: ir_version is \
128         required and ONNX IR versions start at 1. Expected: emit a model with ir_version >= 1"
129    )]
130    InvalidIrVersion { ir_version: i64 },
131
132    #[error(
133        "illegal ONNX model: ir_version {ir_version} requires at least one opset_import \
134         (ONNX IR>=3). Expected: add an opset_import for every operator domain used by the \
135         model"
136    )]
137    MissingModelOpsetImport { ir_version: i64 },
138
139    #[error(
140        "illegal ONNX model: initializer '{tensor}' in an outer graph is shadowed by a \
141         subgraph input of the same name. RULES #1: this runtime does not permit ambiguous \
142         initializer/subgraph binding. Expected: rename the subgraph formal input or the \
143         outer initializer"
144    )]
145    SubgraphInputShadowsInitializer { tensor: String },
146
147    #[error(
148        "illegal ONNX model: graph output '{tensor}' has no producer in its graph. RULES #1: \
149         every output must be a graph input, initializer, or node output in the same scope. \
150         Expected: produce '{tensor}' locally or declare it as an input/initializer"
151    )]
152    GraphOutputMissingProducer { tensor: String },
153
154    #[error("external data file not found: {path}")]
155    ExternalDataNotFound { path: PathBuf },
156
157    #[error("external data path rejected ({reason}): {path}")]
158    ExternalDataPath { path: String, reason: &'static str },
159
160    #[error("weight mmap failed: {0}")]
161    Mmap(String),
162
163    #[error("EPContext node error: {0}")]
164    EpContext(String),
165
166    #[error("EPContext external path rejected ({reason}): {path}")]
167    EpContextPath { path: String, reason: &'static str },
168
169    #[error("graph construction failed: {0}")]
170    GraphBuild(String),
171
172    #[error(
173        "illegal ONNX model: model-local function {function} is recursive (call chain: \
174         {chain}). RULES #1: ONNX function bodies may reference other model-local functions \
175         but MUST NOT be recursive — inlining cannot terminate. Expected: break the cycle so \
176         no function transitively calls itself"
177    )]
178    RecursiveFunction { function: String, chain: String },
179
180    #[error(
181        "illegal ONNX model: call to model-local function {function} at node {node} passes \
182         {actual} {kind}(s) but the function declares only {formal}. RULES #1: a function \
183         call may omit trailing optional {kind}s but must not supply more than are declared. \
184         Expected: remove the extra {kind}(s) or fix the function signature"
185    )]
186    FunctionArityMismatch {
187        function: String,
188        node: String,
189        kind: &'static str,
190        formal: usize,
191        actual: usize,
192    },
193
194    #[error(
195        "illegal ONNX model: call to model-local function {function} at node {node} is missing \
196         required attribute '{attribute}', and the function declares no default for it. \
197         RULES #1: an attribute listed in FunctionProto.attribute has no default and must be \
198         supplied at every call site. Expected: set '{attribute}' on the call node, or give \
199         the function a default via attribute_proto"
200    )]
201    MissingRequiredFunctionAttribute {
202        function: String,
203        node: String,
204        attribute: String,
205    },
206
207    #[error("unsupported ONNX data_type {raw} at {context}")]
208    UnsupportedDataType { raw: i32, context: String },
209
210    #[error("shape inference failed: {0}")]
211    ShapeInference(#[from] onnx_runtime_shape_inference::ShapeInferError),
212
213    #[error(transparent)]
214    Ir(#[from] onnx_runtime_ir::IrError),
215}