Skip to main content

nap_core/
error.rs

1//! Error types for the Narrative Addressing Protocol.
2//!
3//! All NAP errors are surfaced through [`NapError`], which captures the exact
4//! failure domain (URI parsing, manifest I/O, VCS operations, resolution, etc.)
5//! with enough context for callers to produce actionable diagnostics.
6
7use thiserror::Error;
8
9/// Top-level error type for all NAP operations.
10#[derive(Error, Debug)]
11pub enum NapError {
12    // ── URI Errors ──────────────────────────────────────────────────────
13    #[error("invalid NAP URI '{uri}': {reason}")]
14    InvalidUri { uri: String, reason: String },
15
16    #[error("unknown entity type '{0}'")]
17    UnknownEntityType(String),
18
19    // ── Manifest Errors ─────────────────────────────────────────────────
20    #[error("manifest not found: {0}")]
21    ManifestNotFound(String),
22
23    #[error("manifest parse error for '{path}': {source}")]
24    ManifestParseError {
25        path: String,
26        source: serde_yaml::Error,
27    },
28
29    #[error("manifest validation error: {0}")]
30    ManifestValidationError(String),
31
32    #[error("manifest write error for '{path}': {source}")]
33    ManifestWriteError {
34        path: String,
35        source: std::io::Error,
36    },
37
38    // ── Query Errors ────────────────────────────────────────────────────
39    #[error("query path not found: '{path}' in manifest '{manifest_id}'")]
40    QueryPathNotFound { path: String, manifest_id: String },
41
42    #[error("invalid query path: '{0}'")]
43    InvalidQueryPath(String),
44
45    // ── Repository Errors ───────────────────────────────────────────────
46    #[error("repository not found at '{0}'")]
47    RepositoryNotFound(String),
48
49    #[error("repository already exists at '{0}'")]
50    RepositoryAlreadyExists(String),
51
52    #[error("universe '{0}' not found in repository root")]
53    UniverseNotFound(String),
54
55    // ── VCS Errors ──────────────────────────────────────────────────────
56    #[error("VCS error: {0}")]
57    VcsError(String),
58
59    #[error("ref not found: '{0}'")]
60    RefNotFound(String),
61
62    // ── Content Addressing Errors ───────────────────────────────────────
63    #[error("content hash mismatch: expected {expected}, got {actual}")]
64    ContentHashMismatch { expected: String, actual: String },
65
66    // ── I/O ─────────────────────────────────────────────────────────────
67    #[error("I/O error: {0}")]
68    Io(#[from] std::io::Error),
69
70    // ── Merge Errors ────────────────────────────────────────────────────
71    #[error("merge conflict at '{path}': {details}")]
72    MergeConflict { path: String, details: String },
73
74    #[error("SDL parse error: {0}")]
75    SdlParseError(String),
76
77    #[error("SDL validation error: {reason}")]
78    SdlValidationError { reason: String },
79
80    #[error("merge strategy error at '{path}': {reason}")]
81    MergeStrategyError { path: String, reason: String },
82
83    #[error("merge validation error: {reason}")]
84    MergeValidationError { reason: String },
85
86    // ── Permission ──────────────────────────────────────────────────────
87    #[error("permission denied: {0}")]
88    PermissionDenied(String),
89
90    // ── gRPC ─────────────────────────────────────────────────────────────
91    #[error("gRPC error: {0}")]
92    GrpcError(String),
93
94    // ── Catch-all ───────────────────────────────────────────────────────
95    #[error("{0}")]
96    Other(String),
97}
98
99/// Result type alias using [`NapError`].
100pub type NapResult<T> = Result<T, NapError>;