Skip to main content

vasari_core/
error.rs

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/// Typed degradation reasons for the shared ingest pipeline.
34///
35/// The adapter layer returns these rather than panicking when sessions
36/// have missing fields. The caller decides whether to skip or surface.
37#[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}