#[non_exhaustive]pub enum RuntimeError {
PolicyDenied(PolicyError),
PlanContract(String),
UnknownTenant(String),
PolicyBundleChanged {
recorded: Option<Digest>,
configured: Option<Digest>,
},
CanonicalizationChanged {
recorded: u16,
implemented: u16,
},
NoProvider {
target: String,
available: Vec<String>,
},
QuotaExceeded(QuotaError),
ChainBroken {
seq: Seq,
detail: String,
},
Fenced {
run: String,
held: u64,
current: u64,
},
LeaseHeld {
run: String,
owner: String,
remaining_secs: u64,
},
Store(StoreError),
Encoding(Error),
}Expand description
Failures reaching the operator.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
PolicyDenied(PolicyError)
PlanContract(String)
UnknownTenant(String)
This process serves no plane for the tenant named.
Refused rather than defaulted, which is the whole point: a fallback plane would answer an unregistered tenant with somebody else’s data, and it would look exactly like working software.
PolicyBundleChanged
An open run would continue under policy semantics other than the bundle recorded at admission.
CanonicalizationChanged
The history was written under a different canonicalization rule.
Not a divergence, and reporting it as one is the defect this exists to remove: every effect key comes out of the canonicalizer, so a rule change moves all of them at once and a healthy run replays as non-determinism. The run is unverifiable by this build, which is a different claim and the one the evidence supports.
The journal chain is unaffected — it hashes the bytes it stored rather than re-canonicalizing them — so the history is intact and readable; it simply cannot be re-derived here. Before format freeze the answer is to recreate; after it, a build that means to read old history implements the old rule and selects on this number.
NoProvider
Nothing on this plane answers to the name run was given.
Carries what the plane does provide, because the question a reader has next is always “then what should I have asked for?” — and the plane is the only party that can answer it. A refusal that names the missing thing and not the available ones sends somebody back to their own source to reconstruct a list this error was already holding.
Fields
QuotaExceeded(QuotaError)
The tenant is at a ceiling, so nothing was admitted.
Distinct from a policy denial, because they call for opposite responses. A denial says you may not, and retrying is pointless. A quota refusal says not right now, and the caller should come back — a concurrency ceiling clears when a run finishes. Collapsing them would teach callers to retry denials or to give up on back-pressure.
ChainBroken
The journal’s hash chain does not verify. Either a record was altered after the fact, or a writer produced bytes it did not hash.
Fenced
A write was rejected because another instance owns this run at a higher epoch. Not an error to retry blindly: this instance has been fenced and must drop the run.
LeaseHeld
Another instance holds a live lease on this run. Retryable after the
lease expires — unlike Fenced, which never is.
Store(StoreError)
Encoding(Error)
Implementations§
Source§impl RuntimeError
impl RuntimeError
Sourcepub fn from_store(e: StoreError) -> Self
pub fn from_store(e: StoreError) -> Self
Lift a store error into the operator-facing taxonomy.
Two promotions matter, because both change what a human should do:
- Fenced — “I lost ownership of this run” (drop it; another instance has it), as opposed to “the database is unhappy” (retry).
- Corrupt →
ChainBroken— the journal does not verify. That is never a retryable storage hiccup; it means the history has been altered and nothing downstream of it can be trusted. Leaving it as a generic store error would bury the one failure that must never be shrugged off.
Sourcepub fn is_terminal_for_owner(&self) -> bool
pub fn is_terminal_for_owner(&self) -> bool
Whether this run should be abandoned by this instance rather than retried. Both cases are terminal for the current owner: fencing means someone else owns it, and a broken chain means the recorded history can no longer be trusted to describe anything.
Divergence is deliberately not here. It is not a RuntimeError at all —
a replay that recomputes a different key quarantines the run, through
StepError::NonDeterminism, and a run status is not something an
owner abandons. A second spelling of it lived on this enum, unconstructed
and pointed at by the crate’s own front page, until a guard noticed.
Trait Implementations§
Source§impl Debug for RuntimeError
impl Debug for RuntimeError
Source§impl Display for RuntimeError
impl Display for RuntimeError
Source§impl Error for RuntimeError
impl Error for RuntimeError
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()
Source§impl From<Error> for RuntimeError
impl From<Error> for RuntimeError
Source§impl From<PolicyError> for RuntimeError
impl From<PolicyError> for RuntimeError
Source§fn from(source: PolicyError) -> Self
fn from(source: PolicyError) -> Self
Source§impl From<QuotaError> for RuntimeError
impl From<QuotaError> for RuntimeError
Source§fn from(source: QuotaError) -> Self
fn from(source: QuotaError) -> Self
Source§impl From<StoreError> for RuntimeError
impl From<StoreError> for RuntimeError
Source§fn from(source: StoreError) -> Self
fn from(source: StoreError) -> Self
Auto Trait Implementations§
impl !RefUnwindSafe for RuntimeError
impl !UnwindSafe for RuntimeError
impl Freeze for RuntimeError
impl Send for RuntimeError
impl Sync for RuntimeError
impl Unpin for RuntimeError
impl UnsafeUnpin for RuntimeError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more