Skip to main content

khive_vcs/
error.rs

1// Copyright 2026 Haiyang Li. Licensed under Apache-2.0.
2//
3//! Error types for the VCS layer.
4//!
5//! Remote-server and custom-push/pull error variants (`RemoteUnreachable`,
6//! `AuthFailed`, `NonFastForward`, `MergeRequired`) were removed: git is the
7//! remote protocol; there is no custom `khive-sync` server.
8//! `MergeNotImplemented` was removed because the custom merge engine is
9//! superseded for v1.
10
11use thiserror::Error;
12
13use crate::types::SnapshotId;
14
15/// Errors that can occur in the khive VCS layer (snapshot hashing, NDJSON sync, remote fetch).
16#[derive(Debug, Error)]
17pub enum VcsError {
18    /// The archive stored at the remote has a different hash than expected.
19    /// Indicates corruption or tampering.
20    #[error("hash mismatch: expected {expected}, actual {actual}")]
21    HashMismatch {
22        expected: SnapshotId,
23        actual: SnapshotId,
24    },
25
26    /// `checkout` was blocked because there are uncommitted changes.
27    /// Pass `force: true` to discard them.
28    #[error("uncommitted changes: {count} entities/edges modified since last commit")]
29    UncommittedChanges { count: usize },
30
31    /// A `SnapshotId` string failed validation.
32    #[error("invalid snapshot id: {0}")]
33    InvalidSnapshotId(String),
34
35    /// A branch name failed validation (must match `^[a-zA-Z0-9_-]{1,64}$`).
36    #[error("invalid branch name: {0:?}")]
37    InvalidBranchName(String),
38
39    /// A remote name failed validation (must be a single path segment
40    /// matching `[A-Za-z0-9._-]+`, and not `.` or `..`). Rejected before any
41    /// filesystem path is built from it, to prevent path traversal into
42    /// `.khive/kg/remotes/`.
43    #[error("invalid remote name {0:?}: must be one path segment [A-Za-z0-9._-]+ and not . or ..")]
44    InvalidRemoteName(String),
45
46    /// An underlying storage operation failed.
47    #[error("storage: {0}")]
48    Storage(String),
49
50    /// JSON serialization or deserialization failed.
51    #[error("json: {0}")]
52    Json(#[from] serde_json::Error),
53
54    /// An I/O operation failed (file system).
55    #[error("io: {0}")]
56    Io(#[from] std::io::Error),
57
58    /// An unexpected internal error.
59    #[error("internal: {0}")]
60    Internal(String),
61}
62
63impl From<khive_runtime::error::RuntimeError> for VcsError {
64    fn from(e: khive_runtime::error::RuntimeError) -> Self {
65        VcsError::Storage(e.to_string())
66    }
67}