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    // ── Manifest Errors ─────────────────────────────────────────────────
17    #[error("manifest not found: {0}")]
18    ManifestNotFound(String),
19
20    #[error("manifest parse error for '{path}': {source}")]
21    ManifestParseError {
22        path: String,
23        source: serde_yaml::Error,
24    },
25
26    #[error("manifest validation error: {0}")]
27    ManifestValidationError(String),
28
29    #[error("manifest write error for '{path}': {source}")]
30    ManifestWriteError {
31        path: String,
32        source: std::io::Error,
33    },
34
35    // ── Query Errors ────────────────────────────────────────────────────
36    #[error("query path not found: '{path}' in manifest '{manifest_id}'")]
37    QueryPathNotFound { path: String, manifest_id: String },
38
39    #[error("invalid query path: '{0}'")]
40    InvalidQueryPath(String),
41
42    // ── Repository Errors ───────────────────────────────────────────────
43    #[error("repository not found at '{0}'")]
44    RepositoryNotFound(String),
45
46    #[error("repository already exists at '{0}'")]
47    RepositoryAlreadyExists(String),
48
49    // ── Entity Type Errors ─────────────────────────────────────────────
50    #[error("entity type not found: '{0}'")]
51    EntityTypeNotFound(String),
52
53    // ── VCS Errors ──────────────────────────────────────────────────────
54    #[error("VCS error: {0}")]
55    VcsError(String),
56
57    #[error("ref not found: '{0}'")]
58    RefNotFound(String),
59
60    // ── Version-control backend errors ──────────────────────────────────
61    #[error(
62        "cannot {operation}: no version-control backend is configured. \
63         Filesystem state is preserved, but history/sync is unavailable. \
64         Configure one with 'nap backend configure'."
65    )]
66    BackendNotConfigured { operation: String },
67
68    #[error("version-control backend is unavailable: {message}")]
69    BackendUnavailable { message: String },
70
71    #[error("version-control backend operation failed ({operation}): {message}")]
72    BackendOperationFailed { operation: String, message: String },
73
74    // ── Content Addressing Errors ───────────────────────────────────────
75    #[error("content hash mismatch: expected {expected}, got {actual}")]
76    ContentHashMismatch { expected: String, actual: String },
77
78    // ── I/O ─────────────────────────────────────────────────────────────
79    #[error("I/O error: {0}")]
80    Io(#[from] std::io::Error),
81
82    // ── Merge Errors ────────────────────────────────────────────────────
83    #[error("merge conflict at '{path}': {details}")]
84    MergeConflict { path: String, details: String },
85
86    #[error("SDL parse error: {0}")]
87    SdlParseError(String),
88
89    #[error("SDL validation error: {reason}")]
90    SdlValidationError { reason: String },
91
92    #[error("merge strategy error at '{path}': {reason}")]
93    MergeStrategyError { path: String, reason: String },
94
95    #[error("merge validation error: {reason}")]
96    MergeValidationError { reason: String },
97
98    // ── Resolution Errors ───────────────────────────────────────────────
99    #[error("no branch or commit specified and no default_branch configured. ")]
100    NoDefaultBranch,
101
102    #[error("unable to resolve resource '{address}': {message}")]
103    ResolutionFailed { address: String, message: String },
104
105    // ── Permission ──────────────────────────────────────────────────────
106    #[error("permission denied: {0}")]
107    PermissionDenied(String),
108
109    // ── gRPC ─────────────────────────────────────────────────────────────
110    #[error("gRPC error: {0}")]
111    GrpcError(String),
112
113    // ── Catch-all ───────────────────────────────────────────────────────
114    #[error("{0}")]
115    Other(String),
116}
117
118/// Result type alias using [`NapError`].
119pub type NapResult<T> = Result<T, NapError>;