Skip to main content

edgefirst_decoder/model_config/
error.rs

1// SPDX-FileCopyrightText: Copyright 2026 Au-Zone Technologies
2// SPDX-License-Identifier: Apache-2.0
3
4//! [`ModelConfigError`], returned by model configuration discovery.
5
6use std::fmt;
7use std::path::PathBuf;
8
9use crate::{DecoderError, InferError};
10
11/// Why a model configuration could not be read or resolved.
12#[derive(Debug)]
13#[non_exhaustive]
14pub enum ModelConfigError {
15    /// A file could not be read.
16    Io {
17        /// The file.
18        path: PathBuf,
19        /// The underlying error.
20        source: std::io::Error,
21    },
22    /// A model container is malformed where its metadata is stored.
23    Container(String),
24    /// A recognised configuration file has a malformed field.
25    InvalidField {
26        /// The file, e.g. `config.json`.
27        file: String,
28        /// The field, e.g. `id2label`.
29        field: String,
30        /// What is wrong with it.
31        reason: String,
32    },
33    /// A recognised field asks for something the HAL cannot do.
34    NotSupported {
35        /// The field, e.g. `size.shortest_edge`.
36        field: String,
37        /// Why it is not supported.
38        reason: String,
39    },
40    /// A Hugging Face architecture with no decoder mapping, named by its
41    /// `model_type`.
42    UnsupportedArchitecture(String),
43    /// An override is malformed or cannot apply to this model.
44    Override(String),
45    /// The `labels` override names a different number of classes than the
46    /// model has.
47    LabelCountMismatch {
48        /// The model's class count.
49        expected: usize,
50        /// The number of names the override gives.
51        found: usize,
52    },
53    /// Nothing supplied a required piece of the configuration.
54    Unresolved {
55        /// What is missing.
56        missing: String,
57        /// The overrides or files that would supply it.
58        overrides: String,
59    },
60    /// Ultralytics metadata was found but could not be interpreted.
61    Infer(InferError),
62    /// A configuration was found but is not a valid schema.
63    Schema(DecoderError),
64}
65
66impl fmt::Display for ModelConfigError {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        match self {
69            Self::Io { path, source } => write!(f, "cannot read {}: {source}", path.display()),
70            Self::Container(s) => write!(f, "malformed model container: {s}"),
71            Self::InvalidField {
72                file,
73                field,
74                reason,
75            } => write!(f, "{file}: field `{field}` {reason}"),
76            Self::NotSupported { field, reason } => {
77                write!(f, "`{field}` is not supported: {reason}")
78            }
79            Self::UnsupportedArchitecture(t) => write!(
80                f,
81                "Hugging Face model_type `{t}` has no decoder; supported: *ForSemanticSegmentation"
82            ),
83            Self::Override(s) => write!(f, "invalid override: {s}"),
84            Self::LabelCountMismatch { expected, found } => write!(
85                f,
86                "invalid override: labels names {found} classes but the model has {expected}"
87            ),
88            Self::Unresolved { missing, overrides } => {
89                write!(f, "missing {missing}; supply {overrides}")
90            }
91            Self::Infer(e) => write!(f, "Ultralytics metadata: {e}"),
92            Self::Schema(e) => write!(f, "invalid model schema: {e}"),
93        }
94    }
95}
96
97impl std::error::Error for ModelConfigError {
98    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
99        match self {
100            Self::Io { source, .. } => Some(source),
101            Self::Infer(e) => Some(e),
102            Self::Schema(e) => Some(e),
103            _ => None,
104        }
105    }
106}
107
108impl From<InferError> for ModelConfigError {
109    fn from(e: InferError) -> Self {
110        Self::Infer(e)
111    }
112}
113
114impl From<DecoderError> for ModelConfigError {
115    fn from(e: DecoderError) -> Self {
116        Self::Schema(e)
117    }
118}
119
120pub(crate) fn invalid(file: &str, field: &str, reason: impl Into<String>) -> ModelConfigError {
121    ModelConfigError::InvalidField {
122        file: file.to_owned(),
123        field: field.to_owned(),
124        reason: reason.into(),
125    }
126}