loro_common/
error.rs

1use serde_columnar::ColumnarError;
2use thiserror::Error;
3
4use crate::{ContainerID, InternalString, PeerID, TreeID, ID};
5
6pub type LoroResult<T> = Result<T, LoroError>;
7
8#[derive(Error, Debug, PartialEq)]
9pub enum LoroError {
10    #[error("Context's client_id({found:?}) does not match Container's client_id({expected:?})")]
11    UnmatchedContext { expected: PeerID, found: PeerID },
12    #[error("Decode error: Version vector error. Please provide correct version.")]
13    DecodeVersionVectorError,
14    #[error("Decode error: ({0})")]
15    DecodeError(Box<str>),
16    #[error(
17        // This should not happen after v1.0.0
18        "Decode error: The data is either corrupted or originates from an older version that is incompatible due to a breaking change."
19    )]
20    DecodeDataCorruptionError,
21    #[error("Decode error: Checksum mismatch. The data is corrupted.")]
22    DecodeChecksumMismatchError,
23    #[error("Decode error: Encoding version \"{0}\" is incompatible. Loro's encoding is backward compatible but not forward compatible. Please upgrade the version of Loro to support this version of the exported data.")]
24    IncompatibleFutureEncodingError(usize),
25    #[error("Js error ({0})")]
26    JsError(Box<str>),
27    #[error("Cannot get lock or the lock is poisoned")]
28    LockError,
29    #[error("Each AppState can only have one transaction at a time")]
30    DuplicatedTransactionError,
31    #[error("Cannot find ({0})")]
32    NotFoundError(Box<str>),
33    #[error("Transaction error ({0})")]
34    TransactionError(Box<str>),
35    #[error("Index out of bound. The given pos is {pos}, but the length is {len}. {info}")]
36    OutOfBound {
37        pos: usize,
38        len: usize,
39        info: Box<str>,
40    },
41    #[error("Every op id should be unique. ID {id} has been used. You should use a new PeerID to edit the content. ")]
42    UsedOpID { id: ID },
43    #[error("Concurrent ops with the same peer id is not allowed. PeerID: {peer}, LastCounter: {last_counter}, CurrentCounter: {current}")]
44    ConcurrentOpsWithSamePeerID {
45        peer: PeerID,
46        last_counter: i32,
47        current: i32,
48    },
49    #[error("Movable Tree Error: {0}")]
50    TreeError(#[from] LoroTreeError),
51    #[error("Invalid argument ({0})")]
52    ArgErr(Box<str>),
53    #[error("Auto commit has not started. The doc is readonly when detached and detached editing is not enabled.")]
54    AutoCommitNotStarted,
55    #[error("Style configuration missing for \"({0:?})\". Please provide the style configuration using `configTextStyle` on your Loro doc.")]
56    StyleConfigMissing(InternalString),
57    #[error("Unknown Error ({0})")]
58    Unknown(Box<str>),
59    #[error("The given ID ({0}) is not contained by the doc")]
60    FrontiersNotFound(ID),
61    #[error("Cannot import when the doc is in a transaction")]
62    ImportWhenInTxn,
63    #[error("The given method ({method}) is not allowed when the container is detached. You should insert the container to the doc first.")]
64    MisuseDetachedContainer { method: &'static str },
65    #[error("Not implemented: {0}")]
66    NotImplemented(&'static str),
67    #[error("Reattach a container that is already attached")]
68    ReattachAttachedContainer,
69    #[error("Edit is not allowed when the doc is in the detached mode.")]
70    EditWhenDetached,
71    #[error("The given ID ({0}) is not contained by the doc")]
72    UndoInvalidIdSpan(ID),
73    #[error("PeerID cannot be changed. Expected: {expected:?}, Actual: {actual:?}")]
74    UndoWithDifferentPeerId { expected: PeerID, actual: PeerID },
75    #[error("The input JSON schema is invalid")]
76    InvalidJsonSchema,
77    #[error("Cannot insert or delete utf-8 in the middle of the codepoint in Unicode")]
78    UTF8InUnicodeCodePoint { pos: usize },
79    #[error("Cannot insert or delete utf-16 in the middle of the codepoint in Unicode")]
80    UTF16InUnicodeCodePoint { pos: usize },
81    #[error("The end index cannot be less than the start index")]
82    EndIndexLessThanStartIndex { start: usize, end: usize },
83    #[error("Invalid root container name! Don't include '/' or '\\0'")]
84    InvalidRootContainerName,
85    #[error("Import Failed: The dependencies of the importing updates are not included in the shallow history of the doc.")]
86    ImportUpdatesThatDependsOnOutdatedVersion,
87    #[error(
88        "You cannot switch a document to a version before the shallow history's start version."
89    )]
90    SwitchToVersionBeforeShallowRoot,
91    #[error(
92        "The container {container} is deleted. You cannot apply the op on a deleted container."
93    )]
94    ContainerDeleted { container: Box<ContainerID> },
95    #[error("You cannot set the `PeerID` with `PeerID::MAX`, which is an internal specific value")]
96    InvalidPeerID,
97    #[error("The containers {containers:?} are not found in the doc")]
98    ContainersNotFound { containers: Box<Vec<ContainerID>> },
99}
100
101#[derive(Error, Debug, PartialEq)]
102pub enum LoroTreeError {
103    #[error("`Cycle move` occurs when moving tree nodes.")]
104    CyclicMoveError,
105    #[error("The provided parent id is invalid")]
106    InvalidParent,
107    #[error("The parent of tree node is not found {0:?}")]
108    TreeNodeParentNotFound(TreeID),
109    #[error("TreeID {0:?} doesn't exist")]
110    TreeNodeNotExist(TreeID),
111    #[error("The index({index}) should be <= the length of children ({len})")]
112    IndexOutOfBound { len: usize, index: usize },
113    #[error("Fractional index is not enabled, you should enable it first by `LoroTree::set_enable_fractional_index`")]
114    FractionalIndexNotEnabled,
115    #[error("TreeID {0:?} is deleted or does not exist")]
116    TreeNodeDeletedOrNotExist(TreeID),
117}
118
119#[non_exhaustive]
120#[derive(Error, Debug, PartialEq)]
121pub enum LoroEncodeError {
122    #[error("The frontiers are not found in this doc: {0}")]
123    FrontiersNotFound(String),
124    #[error("Shallow snapshot incompatible with old snapshot format. Use new snapshot format or avoid shallow snapshots for storage.")]
125    ShallowSnapshotIncompatibleWithOldFormat,
126    #[error("Cannot export shallow snapshot with unknown container type. Please upgrade the Loro version.")]
127    UnknownContainer,
128}
129
130#[cfg(feature = "wasm")]
131pub mod wasm {
132    use wasm_bindgen::JsValue;
133
134    use crate::{LoroEncodeError, LoroError};
135
136    impl From<LoroError> for JsValue {
137        fn from(value: LoroError) -> Self {
138            JsValue::from_str(&value.to_string())
139        }
140    }
141
142    impl From<LoroEncodeError> for JsValue {
143        fn from(value: LoroEncodeError) -> Self {
144            JsValue::from_str(&value.to_string())
145        }
146    }
147
148    impl From<JsValue> for LoroError {
149        fn from(v: JsValue) -> Self {
150            Self::JsError(
151                v.as_string()
152                    .unwrap_or_else(|| "unknown error".to_owned())
153                    .into_boxed_str(),
154            )
155        }
156    }
157}
158
159impl From<ColumnarError> for LoroError {
160    fn from(e: ColumnarError) -> Self {
161        match e {
162            ColumnarError::ColumnarDecodeError(_)
163            | ColumnarError::RleEncodeError(_)
164            | ColumnarError::RleDecodeError(_)
165            | ColumnarError::OverflowError => {
166                LoroError::DecodeError(format!("Failed to decode Columnar: {}", e).into_boxed_str())
167            }
168            e => LoroError::Unknown(e.to_string().into_boxed_str()),
169        }
170    }
171}