1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2026 aphrody contributors
//! Typed errors for the RAG store, embedding, and search pipeline.
use std::path::PathBuf;
use thiserror::Error;
/// Result type alias for RAG operations.
pub type Result<T, E = RagError> = std::result::Result<T, E>;
/// Errors produced by the RAG pipeline.
#[derive(Debug, Error)]
pub enum RagError {
/// SQLite database error.
#[error("SQLite database error: {0}")]
Sqlite(#[from] rusqlite::Error),
/// I/O error during filesystem indexing or reading.
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
/// HTTP request error (embedder or reranker endpoints).
#[error("HTTP error: {0}")]
Http(#[from] reqwest::Error),
/// JSON serialization/deserialization error.
#[error("JSON error: {0}")]
Serde(#[from] serde_json::Error),
/// Embedding computation failed.
#[error("embedding generation failed: {0}")]
EmbeddingFailed(String),
/// Reranking failed.
#[error("reranker failed: {0}")]
RerankFailed(String),
/// Vector dimension mismatch against active model.
#[error("vector dimension mismatch: expected {expected}, found {found}")]
DimensionMismatch {
/// Expected dimension of the active embedding space.
expected: usize,
/// Observed vector dimension.
found: usize,
},
/// Model space mismatch: attempt to mix vectors from different embedding models.
#[error("embedding model mismatch: database has `{expected}`, query used `{found}`")]
ModelMismatch {
/// Active model in index.
expected: String,
/// Model requested by caller.
found: String,
},
/// Document not found in store.
#[error("document not found: `{0}`")]
DocumentNotFound(String),
/// Indexing failure for a path.
#[error("indexing failed for `{path}`: {message}")]
IndexFailed {
/// Target path.
path: PathBuf,
/// Failure explanation.
message: String,
},
/// Other unexpected pipeline error.
#[error("RAG error: {0}")]
Other(String),
/// An explicit dimension override (`APHRODY_AI_EMBED_DIMENSIONS` or its
/// alias `APHRODY_RAG_EMBED_DIM`) disagrees with the local catalog's
/// dimension for the resolved model. Embedding spaces must never mix
/// (CLAUDE.md ยง7): this is always an error, never a silent choice of one
/// value over the other.
#[error(
"{env_var} sets the embedding vector width to {env_dim}, but model `{model}` is \
catalogued at {catalog_dim} dimensions; fix the override or select a different model"
)]
EmbedDimensionMismatch {
/// Canonical or alias environment variable name that supplied `env_dim`.
env_var: &'static str,
/// The overridden dimension.
env_dim: usize,
/// The model id the override applies to.
model: String,
/// The dimension the local catalog declares for `model`.
catalog_dim: usize,
},
/// The resolved embedding model has no catalog entry (a raw reference
/// such as an unlisted HuggingFace repo) and no dimension override or
/// `[rag] vector_dim` supplies one either.
#[error(
"model `{model}` is not in the local catalog and no vector width is configured; set \
`rag.vector_dim`, `APHRODY_AI_EMBED_DIMENSIONS`, or use a catalogued model"
)]
UnknownEmbedDimension {
/// The model id that could not be resolved to a dimension.
model: String,
},
/// `APHRODY_AI_EMBED_DIMENSIONS` (or its alias) is not a positive integer.
#[error("{env_var}={raw:?} is not a positive integer: {source}")]
InvalidEmbedDimension {
/// The environment variable that carried the malformed value.
env_var: &'static str,
/// The raw value that failed to parse.
raw: String,
/// The underlying parse failure.
#[source]
source: std::num::ParseIntError,
},
/// `embed_backend` needs an HTTP endpoint (`LlamaServer` / `OpenaiCompat`)
/// but none was resolved from `rag.embed_endpoint`,
/// `APHRODY_AI_EMBED_BASE_URL`, or its aliases.
#[error(
"rag.embed_endpoint (or APHRODY_AI_EMBED_BASE_URL / its aliases) is required for embed_backend={backend:?}"
)]
MissingEmbedEndpoint {
/// The backend that required an endpoint.
backend: aphrody_config::EmbedBackend,
},
/// Reranking was requested but no endpoint was resolved from
/// `rag.rerank_endpoint`, `APHRODY_AI_RERANK_BASE_URL`, or its aliases.
#[error(
"rag.rerank_endpoint (or APHRODY_AI_RERANK_BASE_URL / its aliases) is required when \
reranking is enabled"
)]
MissingRerankEndpoint,
}