1use std::{path::PathBuf, process::ExitStatus, time::Duration};
2
3use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum CodexError {
8 #[error("codex binary `{binary}` could not be spawned: {source}")]
9 Spawn {
10 binary: PathBuf,
11 #[source]
12 source: std::io::Error,
13 },
14 #[error("failed to wait for codex process: {source}")]
15 Wait {
16 #[source]
17 source: std::io::Error,
18 },
19 #[error("codex exceeded timeout of {timeout:?}")]
20 Timeout { timeout: Duration },
21 #[error("codex exited with {status:?}: {stderr}")]
22 NonZeroExit { status: ExitStatus, stderr: String },
23 #[error("codex output was not valid UTF-8: {0}")]
24 InvalidUtf8(#[from] std::string::FromUtf8Error),
25 #[error("failed to parse {context} JSON output: {source}")]
26 JsonParse {
27 context: &'static str,
28 stdout: String,
29 #[source]
30 source: serde_json::Error,
31 },
32 #[error("failed to parse execpolicy JSON output: {source}")]
33 ExecPolicyParse {
34 stdout: String,
35 #[source]
36 source: serde_json::Error,
37 },
38 #[error("failed to parse features list output: {reason}")]
39 FeatureListParse { reason: String, stdout: String },
40 #[error("failed to read responses-api-proxy server info from `{path}`: {source}")]
41 ResponsesApiProxyInfoRead {
42 path: PathBuf,
43 #[source]
44 source: std::io::Error,
45 },
46 #[error("failed to parse responses-api-proxy server info from `{path}`: {source}")]
47 ResponsesApiProxyInfoParse {
48 path: PathBuf,
49 #[source]
50 source: serde_json::Error,
51 },
52 #[error("prompt must not be empty")]
53 EmptyPrompt,
54 #[error("sandbox command must not be empty")]
55 EmptySandboxCommand,
56 #[error("execpolicy command must not be empty")]
57 EmptyExecPolicyCommand,
58 #[error("API key must not be empty")]
59 EmptyApiKey,
60 #[error("task id must not be empty")]
61 EmptyTaskId,
62 #[error("environment id must not be empty")]
63 EmptyEnvId,
64 #[error("MCP server name must not be empty")]
65 EmptyMcpServerName,
66 #[error("MCP server command must not be empty")]
67 EmptyMcpCommand,
68 #[error("MCP server URL must not be empty")]
69 EmptyMcpUrl,
70 #[error("socket path must not be empty")]
71 EmptySocketPath,
72 #[error("failed to create temporary working directory: {0}")]
73 TempDir(#[source] std::io::Error),
74 #[error("failed to resolve working directory: {source}")]
75 WorkingDirectory {
76 #[source]
77 source: std::io::Error,
78 },
79 #[error("failed to prepare app-server output directory `{path}`: {source}")]
80 PrepareOutputDirectory {
81 path: PathBuf,
82 #[source]
83 source: std::io::Error,
84 },
85 #[error("failed to prepare CODEX_HOME at `{path}`: {source}")]
86 PrepareCodexHome {
87 path: PathBuf,
88 #[source]
89 source: std::io::Error,
90 },
91 #[error("codex stdout unavailable")]
92 StdoutUnavailable,
93 #[error("codex stderr unavailable")]
94 StderrUnavailable,
95 #[error("codex stdin unavailable")]
96 StdinUnavailable,
97 #[error("failed to capture codex output: {0}")]
98 CaptureIo(#[from] std::io::Error),
99 #[error("failed to write prompt to codex stdin: {0}")]
100 StdinWrite(#[source] std::io::Error),
101 #[error("failed to join codex output task: {0}")]
102 Join(#[from] tokio::task::JoinError),
103}