1use thiserror::Error;
2
3#[derive(Debug, Error)]
4pub enum VasariError {
5 #[error("node not found: {0}")]
6 NodeNotFound(String),
7 #[error("hash mismatch: expected {expected}, got {actual}")]
8 HashMismatch { expected: String, actual: String },
9 #[error("invalid node id: {0}")]
10 InvalidNodeId(String),
11 #[error("incompatible .vasari store format (found {found}, this vasari needs {expected}) — remove the .vasari directory and re-ingest your sessions")]
12 IncompatibleStore { found: String, expected: String },
13 #[error("ambiguous id prefix '{prefix}' matches {count} nodes — use more characters")]
14 AmbiguousPrefix { prefix: String, count: usize },
15 #[error("no attribution found for {path}:{line} — run `vasari files` to see which paths have coverage, `vasari ingest` to populate the graph, or `vasari fsck` to rebuild the index")]
16 AttributionNotFound { path: String, line: u32 },
17 #[error("plan not found: {0}")]
18 PlanNotFound(String),
19 #[error("plan step index {step_index} out of bounds for plan {plan_id} ({step_count} steps) — graph may be corrupt; run `vasari fsck`")]
20 PlanStepOutOfBounds {
21 plan_id: String,
22 step_index: usize,
23 step_count: usize,
24 },
25 #[error("degraded ingest: {0}")]
26 Degraded(DegradedReason),
27 #[error("io: {0}")]
28 Io(#[from] std::io::Error),
29 #[error("json: {0}")]
30 Json(#[from] serde_json::Error),
31}
32
33#[derive(Debug, Clone)]
38pub enum DegradedReason {
39 MissingTimestamp { tool: String },
40 MissingArgs { tool: String },
41 UnknownTool(String),
42 UnparsableSession { source: String, detail: String },
43 UnparsableSpan { span_name: String, detail: String },
44 EmptySession { source: String },
45}
46
47impl std::fmt::Display for DegradedReason {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 match self {
50 Self::MissingTimestamp { tool } => write!(f, "missing timestamp on tool call '{tool}'"),
51 Self::MissingArgs { tool } => write!(f, "missing args on tool call '{tool}'"),
52 Self::UnknownTool(t) => write!(f, "unknown tool '{t}'"),
53 Self::UnparsableSession { source, detail } => {
54 write!(f, "unparsable session from {source}: {detail}")
55 }
56 Self::UnparsableSpan { span_name, detail } => {
57 write!(f, "unparsable span '{span_name}': {detail}")
58 }
59 Self::EmptySession { source } => {
60 write!(f, "no ingest-relevant events found in session: {source}")
61 }
62 }
63 }
64}