Skip to main content

runx_runtime/
error.rs

1use std::path::PathBuf;
2
3use runx_contracts::AuthorityVerb;
4use runx_core::state_machine::FanoutSyncDecision;
5use thiserror::Error;
6
7use crate::credentials::CredentialDeliveryError;
8
9#[derive(Debug, Error)]
10pub enum RuntimeError {
11    #[error("runtime I/O failed while {context}: {source}")]
12    Io {
13        context: String,
14        #[source]
15        source: std::io::Error,
16    },
17    #[error("graph parse failed: {0}")]
18    ParseGraph(#[from] runx_parser::ParseError),
19    #[error("graph validation failed: {0}")]
20    ValidateGraph(#[from] runx_parser::ValidationError),
21    #[error("JSON serialization failed while {context}: {source}")]
22    Json {
23        context: String,
24        #[source]
25        source: serde_json::Error,
26    },
27    #[error("graph step '{step_id}' is missing")]
28    StepMissing { step_id: String },
29    #[error("graph step '{step_id}' has no skill target")]
30    StepMissingSkill { step_id: String },
31    #[error("graph step '{step_id}' has invalid run configuration: {reason}")]
32    InvalidRunStep { step_id: String, reason: String },
33    #[error("graph step '{step_id}' uses unsupported run type '{run_type}'")]
34    UnsupportedRunStep { step_id: String, run_type: String },
35    #[error("graph step '{step_id}' is blocked: {reason}")]
36    GraphBlocked { step_id: String, reason: String },
37    #[error(
38        "context edge from step '{from_step}' could not resolve path '{output_path}': segment '{missing_segment}' is absent; available keys there: [{}]",
39        .available_keys.join(", ")
40    )]
41    ContextEdgeUnresolved {
42        from_step: String,
43        output_path: String,
44        missing_segment: String,
45        available_keys: Vec<String>,
46    },
47    #[error(
48        "context edge from step '{from_step}' binds base/diagnostic field '{base_field}' (path '{output_path}'); base fields (raw/skill_claim/stdout/stderr/status) are not addressable, bind the step contract (a declared output or artifact packet) instead"
49    )]
50    ContextEdgeBaseKey {
51        from_step: String,
52        output_path: String,
53        base_field: String,
54    },
55    #[error("authority {verb:?} denied graph step '{step_id}': {reason}")]
56    AuthorityDenied {
57        verb: AuthorityVerb,
58        step_id: String,
59        reason: String,
60    },
61    #[error("graph step '{step_id}' failed planning: {reason}")]
62    GraphPlanningFailed { step_id: String, reason: String },
63    #[error("graph step '{step_id}' paused: {reason}")]
64    GraphPaused {
65        step_id: String,
66        reason: String,
67        sync_decision: Box<FanoutSyncDecision>,
68    },
69    #[error("graph step '{step_id}' escalated: {reason}")]
70    GraphEscalated {
71        step_id: String,
72        reason: String,
73        sync_decision: Box<FanoutSyncDecision>,
74    },
75    #[error("checkpoint graph '{checkpoint_graph}' cannot resume graph '{graph}'")]
76    CheckpointGraphMismatch {
77        checkpoint_graph: String,
78        graph: String,
79    },
80    #[error("unsupported adapter '{adapter_type}'")]
81    UnsupportedAdapter { adapter_type: String },
82    #[error("unsupported source kind '{source_kind}'")]
83    UnsupportedSource { source_kind: String },
84    #[error("runner selection '{runner}' is not supported by the native runtime yet")]
85    UnsupportedRunnerSelection { runner: String },
86    #[error("cli-tool source is missing command")]
87    MissingCommand,
88    #[error("sandbox violation: {message}")]
89    SandboxViolation { message: String },
90    #[error("credential delivery failed: {0}")]
91    CredentialDelivery(#[from] CredentialDeliveryError),
92    #[error("effect state failed while {context}: {message}")]
93    EffectState { context: String, message: String },
94    #[error("skill file is missing at {path}")]
95    SkillFileMissing { path: PathBuf },
96    #[error("skill '{skill_name}' failed: {message}")]
97    SkillFailed { skill_name: String, message: String },
98    #[error("receipt validation failed: {message}")]
99    ReceiptInvalid { message: String },
100}
101
102impl RuntimeError {
103    pub(crate) fn io(context: impl Into<String>, source: std::io::Error) -> Self {
104        Self::Io {
105            context: context.into(),
106            source,
107        }
108    }
109
110    pub(crate) fn json(context: impl Into<String>, source: serde_json::Error) -> Self {
111        Self::Json {
112            context: context.into(),
113            source,
114        }
115    }
116
117    pub(crate) fn effect_state(context: impl Into<String>, source: impl std::fmt::Display) -> Self {
118        Self::EffectState {
119            context: context.into(),
120            message: source.to_string(),
121        }
122    }
123}