use std::path::PathBuf;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error(
"refusing secret file or directory: {path} (built-in deny policy cannot be overridden)"
)]
SecretFile { path: PathBuf },
#[error("STT model {reason}; run `seyk setup audio`")]
SttModel { reason: &'static str },
#[error("speech-to-text failed: {reason}")]
SpeechToText { reason: &'static str },
#[error("audio extraction interval exceeds the 30-second request limit")]
AudioIntervalTooLong,
#[error("resource changed while reading: {resource}")]
ChangedWhileReading { resource: crate::ResourceId },
#[error("unsupported audio for {resource}: {reason}")]
UnsupportedAudio {
resource: crate::ResourceId,
reason: &'static str,
},
#[error("PDF rendering failed for {resource}: {reason}")]
PdfRender {
resource: crate::ResourceId,
reason: &'static str,
},
#[error(
"readable text for scanned pages needs OCR, which is not available yet ({resource}, page {page})"
)]
PdfOcrUnavailable {
resource: crate::ResourceId,
page: u32,
},
#[error("PDF parse failed for {resource}: {reason}")]
PdfParse {
resource: crate::ResourceId,
reason: &'static str,
},
#[error("PDF parse failed for {resource}: {reason}")]
PdfPageDecode {
resource: crate::ResourceId,
reason: &'static str,
},
#[error("PDF parser panicked for {resource}: {reason}")]
ParserPanicked {
resource: crate::ResourceId,
reason: &'static str,
},
#[error("I/O error at {path}: {source}")]
Io {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error(
"cache changes committed, but scrub is pending; run seyk cache scrub once other readers close (using the same cache path), or rerun the one-shot command; cache clear is a fallback"
)]
CacheCleanupPending,
#[error("cache error: {0}")]
Cache(#[from] rusqlite::Error),
#[error("embedding backend error: {0}")]
Embedding(String),
#[error("model files not found: {0}")]
ModelNotFound(String),
#[error("{modality} resources are not supported by this embedder")]
UnsupportedModality { modality: crate::Modality },
#[error("task {task:?} is not supported for {modality}")]
UnsupportedTask {
task: seyk_embed::EmbeddingTask,
modality: crate::Modality,
},
#[error("resource changed since search: {resource} (expected {expected}, got {actual})")]
StaleResource {
resource: crate::ResourceId,
expected: String,
actual: String,
},
#[error("extraction is unsupported for {modality} resource {resource} at {locator:?}{note}", note = if *modality == crate::Modality::Audio { "; configure an audio extractor (feature `audio-stt`)" } else { "" })]
UnsupportedExtraction {
resource: crate::ResourceId,
modality: crate::Modality,
locator: crate::ResourceLocator,
},
#[error("invalid locator for {resource}: {reason}")]
InvalidLocator {
resource: crate::ResourceId,
locator: crate::ResourceLocator,
reason: &'static str,
},
#[error("resource {resource} is not valid UTF-8: {source}")]
InvalidText {
resource: crate::ResourceId,
#[source]
source: std::str::Utf8Error,
},
#[error("dimension mismatch: expected {expected}, got {actual}")]
DimensionMismatch { expected: usize, actual: usize },
#[error("invalid configuration: {0}")]
Config(String),
#[error("invalid glob pattern: {0}")]
Glob(#[from] globset::Error),
}
impl Error {
pub(crate) fn io(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
Error::Io {
path: path.into(),
source,
}
}
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
impl From<seyk_embed::Error> for Error {
fn from(error: seyk_embed::Error) -> Self {
match error {
seyk_embed::Error::Io { path, source } => Self::Io { path, source },
seyk_embed::Error::Embedding(message) => Self::Embedding(message),
seyk_embed::Error::ModelNotFound(message) => Self::ModelNotFound(message),
seyk_embed::Error::UnsupportedModality { modality } => {
Self::UnsupportedModality { modality }
}
seyk_embed::Error::DimensionMismatch { expected, actual } => {
Self::DimensionMismatch { expected, actual }
}
seyk_embed::Error::Config(message) => Self::Config(message),
seyk_embed::Error::UnsupportedTask { task, modality } => {
Self::UnsupportedTask { task, modality }
}
other => Self::Embedding(other.to_string()),
}
}
}