Skip to main content

kothok_edge_tts/
error.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 Nayeem Bin Ahsan
3//! Crate-level error type for Edge-TTS synthesis failures.
4
5use thiserror::Error;
6
7/// All ways a synthesis request can fail.
8///
9/// Callers typically propagate this with `?` or match on a variant to
10/// decide whether to retry (e.g. [`TtsError::Connect`] after a network blip).
11#[derive(Debug, Error)]
12pub enum TtsError {
13    /// The WebSocket handshake or DRM-token auth failed after all retry
14    /// attempts. The inner string is the last underlying error message.
15    #[error("ws connect failed after retries: {0}")]
16    Connect(String),
17
18    /// The voice-catalogue HTTPS fetch failed (DNS, transport, HTTP framing).
19    /// The inner string is the underlying error message.
20    #[error("voice fetch failed: {0}")]
21    VoiceFetch(String),
22
23    /// A voice-list JSON body could not be deserialized. The inner string is
24    /// the underlying serde error message.
25    #[error("parse failed: {0}")]
26    Parse(String),
27
28    /// Transport-level WebSocket error (handshake, frame decode, TLS).
29    ///
30    /// The `tungstenite::Error` is boxed to keep `TtsError` small: it is the
31    /// largest variant and threads through every `Result<_, TtsError>` on the
32    /// stack. Boxing it allocates only on the rare error path.
33    #[error("ws: {0}")]
34    Ws(#[source] Box<tokio_tungstenite::tungstenite::Error>),
35
36    /// I/O error on the underlying TCP stream, including receive idle timeout.
37    #[error("io: {0}")]
38    Io(#[from] std::io::Error),
39
40    /// The turn completed (or the stream closed) without any audio frames.
41    #[error("no audio received")]
42    NoAudio,
43}
44
45impl From<tokio_tungstenite::tungstenite::Error> for TtsError {
46    fn from(e: tokio_tungstenite::tungstenite::Error) -> Self {
47        TtsError::Ws(Box::new(e))
48    }
49}