Error Handling
The AppError Enum
TMT uses a single centralised error type defined in src/error.rs using the thiserror crate. Every failure mode in the application is represented as a variant of AppError, which gives callers a single type to match on and provides human-readable messages automatically via the Display trait.
Error Propagation
All fallible functions return Result<T, AppError> and use the ? operator to bubble errors upward. The chain terminates in main.rs, which logs the error and exits with a non-zero status code.
format handler error
│ ?
TranslationService error
│ ?
app::run
│ ?
main ──▶ eprintln! + process::exit(1)
Automatic Conversions
Standard library and third-party error types are automatically converted into AppError variants through From implementations:
| Source Type | AppError Variant |
|---|---|
std::io::Error | AppError::Io |
csv::Error | AppError::Csv |
| HTTP / network errors | AppError::Network (via TmtClient) |
| Rate-limit responses | AppError::RateLimit |
Key Error Variants
| Variant | When it occurs |
|---|---|
MissingApiToken | No token provided via --api-token or TMT_API_TOKEN |
InvalidArgument | A CLI argument fails a business-logic constraint (e.g. concurrency = 0) |
FileTooLarge | The input file exceeds MAX_FILE_SIZE_BYTES |
FormatMismatch | Input and output extensions do not match |
UnsupportedFormat | The file extension is not handled by any format module |
RateLimit | The API responded with HTTP 429 and backoff was exhausted |
Io | Any filesystem read/write failure |
Csv | A parsing error in CSV/TSV content |
DocxParse | A structural error in a DOCX file |
PdfParse | A structural error in a PDF file (pdf feature only) |
Adding New Error Variants
Because AppError uses thiserror, adding a new variant is straightforward:
#![allow(unused)]
fn main() {
#[derive(Debug, thiserror::Error)]
pub enum AppError {
// ... existing variants ...
#[error("my new error: {0}")]
MyNewError(String),
}
}
Implement From<YourLibraryError> if you want automatic ? conversion from a third-party type.