Skip to main content

forge_dictate/
error.rs

1//! Error taxonomy for the crate.
2
3use std::path::PathBuf;
4
5/// Everything this crate can fail with.
6#[derive(Debug, thiserror::Error)]
7pub enum Error {
8    /// No models directory was configured and the platform cache
9    /// directory could not be resolved.
10    #[error("no cache directory available; set Config::models_dir explicitly")]
11    NoCacheDir,
12
13    /// A filesystem operation on `path` failed. A transfer that dies
14    /// mid-body lands here too rather than in [`Error::Http`]: it
15    /// surfaces while reading the response, and `path` labels the
16    /// partial being written rather than naming what actually failed.
17    #[error("{}: {source}", path.display())]
18    Io {
19        path: PathBuf,
20        #[source]
21        source: std::io::Error,
22    },
23
24    /// The request failed before any body arrived - connection, TLS, or
25    /// a refused handshake.
26    #[error("could not fetch {url}: {source}")]
27    Http {
28        url: String,
29        #[source]
30        source: reqwest::Error,
31    },
32
33    /// The server answered, but not with the file.
34    #[error("{url} returned HTTP {status}")]
35    HttpStatus { url: String, status: u16 },
36
37    /// A file on disk is not the length the spec records. The usual
38    /// cause is an interrupted download that was never resumed.
39    #[error("{} is {actual} bytes, expected {expected}", path.display())]
40    SizeMismatch { path: PathBuf, expected: u64, actual: u64 },
41
42    /// Work was stopped on request rather than by a fault: a progress
43    /// callback returning `Break` during a fetch, or an abandoned
44    /// [`crate::Ticket`] aborting an inference.
45    ///
46    /// Whatever already finished is kept - a model that reached
47    /// [`crate::Progress::Ready`] is installed - and any partial transfer
48    /// is left where it is, so a later call resumes rather than starting
49    /// over.
50    #[error("cancelled on request")]
51    Cancelled,
52
53    /// The source declares a rate the models cannot read. Rejected
54    /// rather than resampled: a silent resample yields plausible text
55    /// from the wrong signal, and nothing downstream can detect that.
56    #[error("audio is {actual} Hz, expected {expected} Hz; resample before transcribing")]
57    SampleRate { expected: u32, actual: u32 },
58
59    /// The source declares more than one channel. Interleaved stereo
60    /// read as mono is a plausible doubled-rate signal, not an error, so
61    /// it is refused at the boundary.
62    #[error("audio has {actual} channels, expected mono; downmix before transcribing")]
63    Channels { actual: u16 },
64
65    /// Opening or running the input stream failed.
66    #[error("microphone capture failed: {message}")]
67    Capture { message: String },
68
69    /// The transcription worker could not be started.
70    #[error("could not start the transcription worker: {message}")]
71    WorkerSpawn { message: String },
72
73    /// The weights could not be loaded.
74    #[error("could not load the model at {}: {message}", path.display())]
75    ModelLoad { path: PathBuf, message: String },
76
77    /// Recognition itself failed.
78    #[error("recognition failed: {message}")]
79    Recognition { message: String },
80
81    /// The worker is gone, so nothing can be transcribed and no queued
82    /// result will ever arrive.
83    #[error("the transcription worker has stopped")]
84    EngineStopped,
85
86    /// A partial does not match its spec and could not be removed, so
87    /// every later call fails identically until someone clears it. The
88    /// usual cause is a models directory that is not writable.
89    #[error("{} does not match its spec and could not be removed ({source}); remove it to unblock", path.display())]
90    StalePartial {
91        path: PathBuf,
92        #[source]
93        source: std::io::Error,
94    },
95
96    /// A file on disk is the right length but the wrong bytes.
97    #[error("{} hashes to {actual}, expected {expected}", path.display())]
98    HashMismatch { path: PathBuf, expected: String, actual: String },
99
100    /// A catalogue document is not an entry this build reads.
101    #[error("catalogue: {message}")]
102    Catalogue { message: String },
103
104    /// A bench's corpus could not be read: a wav that is not the shape
105    /// this crate reads, or a fixture set that disagrees with itself.
106    #[error("bench: {message}")]
107    Bench { message: String },
108}