choreo_content/error.rs
1//! Structured error type for the Coordination Platform tools.
2//!
3//! Every `execute_*` entry point returns `Result<T, ContentError>`. The daemon
4//! converts this into a tool execution error via
5//! `impl From<ContentError> for ToolExecError`. Production code never panics —
6//! all failures (subxt/interop, IPFS, indexer, protobuf decode, item-id
7//! derivation, account/keystore, config) are surfaced here.
8
9use thiserror::Error;
10
11/// Errors produced by the Choreographr Coordination Platform tools.
12#[derive(Debug, Error)]
13pub enum ContentError {
14 /// The sidecar tokio runtime was never initialized (or failed to start).
15 #[error("coordinator runtime is not initialized")]
16 RuntimeNotInitialized,
17
18 /// Substrate/subxt transport or interop failure.
19 #[error("substrate error: {0}")]
20 Substrate(String),
21
22 /// The transaction was rejected or could not be submitted.
23 #[error("transaction failed: {0}")]
24 Transaction(String),
25
26 /// The account used to sign is missing from the keystore credential store.
27 #[error("unknown polkadot account: {0}")]
28 UnknownAccount(String),
29
30 /// An IPFS operation failed.
31 #[error("ipfs error: {0}")]
32 Ipfs(String),
33
34 /// An image could not be read, decoded, or JPEG-encoded.
35 #[error("image error: {0}")]
36 Image(String),
37
38 /// The indexer WebSocket API request failed.
39 #[error("indexer error: {0}")]
40 Indexer(String),
41
42 /// A content payload could not be encoded/decoded (protobuf) or a field
43 /// was missing/ill-formed.
44 #[error("content error: {0}")]
45 Content(String),
46
47 /// An item ID could not be derived/decoded, or an argument was invalid.
48 #[error("invalid argument: {0}")]
49 InvalidArgument(String),
50
51 /// A CID or sha2-256 digest could not be converted/parsed.
52 #[error("cid error: {0}")]
53 Cid(String),
54
55 /// The keystore/account operation failed.
56 #[error("account error: {0}")]
57 Account(String),
58
59 /// Any other failure (bounded, informational).
60 #[error("content error: {0}")]
61 Other(String),
62}
63
64impl ContentError {
65 /// Convenience constructor for a plain string error.
66 pub fn other(msg: impl Into<String>) -> Self {
67 ContentError::Other(msg.into())
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn messages_render() {
77 assert_eq!(
78 ContentError::RuntimeNotInitialized.to_string(),
79 "coordinator runtime is not initialized"
80 );
81 assert!(
82 ContentError::Substrate("boom".into())
83 .to_string()
84 .contains("boom")
85 );
86 assert!(
87 ContentError::Account("missing".into())
88 .to_string()
89 .contains("missing")
90 );
91 }
92
93 #[test]
94 fn other_constructor() {
95 assert_eq!(ContentError::other("x").to_string(), "content error: x");
96 }
97}