#[non_exhaustive]pub enum HarnessError {
CapabilityNotSupported {
primitive: String,
},
StaleTarget {
detail: String,
},
Transport {
detail: String,
},
Protocol {
detail: String,
},
Harness {
detail: String,
},
Configuration {
detail: String,
},
Contract {
detail: String,
},
}Expand description
The neutral error taxonomy for the harness-integration seam.
Every arm is harness-neutral. Self::CapabilityNotSupported is the first-class outcome an
observability-only harness returns from crate::AgentSession::intervene for any command —
it is a legitimate, gated rejection, not an internal failure.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
CapabilityNotSupported
The requested intervention primitive is not in the harness’s advertised capability set.
This is the first-class rejection an observability-only harness (empty capability set) returns for every command, and the rejection any harness returns for a primitive it did not advertise. It is a normal, expected outcome of capability gating — not a fault.
StaleTarget
The command targets a stale or unknown activity attempt and is a no-op.
A command addressed to a superseded attempt (a later attempt is now live) or to a session that has already reached its terminal result is dropped without effect.
Transport
The underlying transport failed (spawn/connect failure, broken pipe, EOF, I/O error).
Neutral: it describes that the transport failed and carries the detail, never which transport. An adapter maps its own I/O failures here.
Protocol
A message was received that violates the wire protocol contract.
Malformed framing, an undecodable envelope, a response that correlates to no outstanding request, or a terminal result delivered on the wrong message kind. This signals a bug in the peer or the adapter, distinct from an ordinary transport outage.
Harness
The harness reported an application-level failure while running the agent.
The agent ran but ended in failure (a non-success exit, an error result, a rejected run).
Distinct from Self::Transport (the channel broke) and Self::Protocol (a malformed
message): here the channel and framing were sound and the harness reported failure.
Configuration
The harness cannot be launched as CONFIGURED, so no run was started.
A DETERMINISTIC refusal, and its own variant for the same reason
Self::Contract is: the channel never opened, so Self::Transport is wrong
and would tell an operator a story about a flaky pipe; no frame was exchanged, so
Self::Protocol is wrong; and nothing ran, so Self::Harness is wrong. What
is wrong is a value somebody WROTE — an environment pass-through entry that is a
KEY=VALUE pair instead of a name, a declaration that omits the variable the
program is looked up on. The next attempt reads the same document and meets the
same wall, so retrying spends a worker’s attempt budget to learn nothing. The
worker maps this variant to a TERMINAL activity failure.
Contract
The run completed, but its native outcome cannot satisfy the canonical
agent-outcome contract (AgentOutcome { text, stop_reason }).
A DETERMINISTIC refusal, and that is the whole reason it is its own variant: the channel
was sound (Self::Transport is wrong), the frames were well-formed (Self::Protocol
is wrong — and a protocol fault CAN be a transient peer flake, which this never is), and
the run did not fail (Self::Harness is wrong). The run’s configuration produces an
outcome the seam excludes — e.g. a structured output where the contract’s text demands a
String — so re-running it re-spends a whole agent run to hit the same wall. The worker
maps this variant to a TERMINAL activity failure; every other variant stays retryable.
Implementations§
Source§impl HarnessError
impl HarnessError
Sourcepub fn capability_not_supported(primitive: impl Into<String>) -> Self
pub fn capability_not_supported(primitive: impl Into<String>) -> Self
Builds a Self::CapabilityNotSupported naming the unsupported primitive.
Sourcepub fn stale_target(detail: impl Into<String>) -> Self
pub fn stale_target(detail: impl Into<String>) -> Self
Builds a Self::StaleTarget with a detail message.
Sourcepub fn transport(detail: impl Into<String>) -> Self
pub fn transport(detail: impl Into<String>) -> Self
Builds a Self::Transport with a detail message.
Sourcepub fn protocol(detail: impl Into<String>) -> Self
pub fn protocol(detail: impl Into<String>) -> Self
Builds a Self::Protocol with a detail message.
Sourcepub fn harness(detail: impl Into<String>) -> Self
pub fn harness(detail: impl Into<String>) -> Self
Builds a Self::Harness with a detail message.
Sourcepub fn contract(detail: impl Into<String>) -> Self
pub fn contract(detail: impl Into<String>) -> Self
Builds a Self::Contract with a detail message naming the canonical
agent-outcome contract and what was found instead.
Sourcepub fn configuration(detail: impl Into<String>) -> Self
pub fn configuration(detail: impl Into<String>) -> Self
Builds a Self::Configuration with a detail message naming the setting that
makes the harness unlaunchable.
Sourcepub fn is_deterministic(&self) -> bool
pub fn is_deterministic(&self) -> bool
Whether this error is DETERMINISTIC — a property of how the run is configured, so retrying re-spends a whole agent run to hit the same wall — as opposed to potentially transient (a provider-overload burst, a one-off malformed frame, a dropped pipe, a superseded attempt).
This is THE retry-classification decision for the seam, made here in
the defining crate with an EXHAUSTIVE match — legal despite
#[non_exhaustive] — so adding a variant is a compile error at this
site and its classification is decided on purpose, never defaulted by
a caller’s wildcard arm. The worker maps true to a terminal activity
failure and false to a retryable one.
Per variant:
Self::Contract: deterministic by definition — the run completed and its configured outcome shape cannot satisfy the agent-outcome contract; the next attempt is configured identically.Self::Configuration: deterministic by definition — the launch was refused by a value in the document, and the next attempt reads the same document. A refusal that presented as a transient transport failure would tell the operator the wrong story AND spend the whole attempt budget confirming it.Self::Transport: a broken channel can heal.Self::Protocol: a malformed frame CAN be a one-off peer flake (truncated stream, interleaved write), so it stays retryable even though some protocol faults are in fact permanent.Self::Harness: the run failed; overload and timeouts recur or do not — that judgement belongs to the retry policy.Self::CapabilityNotSupported/Self::StaleTarget: gating and staleness outcomes on the intervention path; when they surface from a result path at all they describe a racing world, not a fixed one.
Trait Implementations§
Source§impl Clone for HarnessError
impl Clone for HarnessError
Source§fn clone(&self) -> HarnessError
fn clone(&self) -> HarnessError
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for HarnessError
impl Debug for HarnessError
Source§impl Display for HarnessError
impl Display for HarnessError
impl Eq for HarnessError
Source§impl Error for HarnessError
impl Error for HarnessError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()