pub enum ServerError {
Show 23 variants
Config {
message: String,
},
UnsafeDataRootAncestor {
data_root: PathBuf,
component: PathBuf,
reason: String,
},
TransportBind {
transport: &'static str,
address: SocketAddr,
message: String,
},
Transport {
transport: &'static str,
message: String,
},
SignalListener {
listener: &'static str,
message: String,
},
DeathNote {
message: String,
},
PidFile {
message: String,
},
HomeAlreadyClaimed {
refusal: Box<HomeAlreadyClaimed>,
},
Incarnation {
message: String,
},
Namespace {
message: String,
},
EngineCall {
source: EngineError,
},
StoreBackend {
source: StoreError,
},
Stream {
failure: StreamFailure,
},
WorkerDispatch {
namespace: String,
activity_type: String,
reason: String,
},
WorkerConnectionLost {
channel: String,
detail: String,
},
WorkerBusy {
channel: String,
detail: String,
},
WorkerDispatchUnservable {
channel: String,
detail: String,
},
PendingActivityCollision {
workflow_id: WorkflowId,
activity_id: ActivityId,
held_attempt: u32,
incoming_attempt: u32,
},
ActivityCompletionRejected {
workflow_id: WorkflowId,
activity_id: ActivityId,
reason: CompletionRejectionReason,
},
DeclaredAttemptCollision {
workflow_id: WorkflowId,
activity_id: ActivityId,
attempt: u32,
},
DrainingRefusedDeclaredAttempt {
workflow_id: WorkflowId,
activity_id: ActivityId,
attempt: u32,
},
LockPoisoned {
resource: &'static str,
},
Wire {
wire: WireError,
},
}Expand description
Server-library error taxonomy.
Variants§
Config
Operator configuration could not be loaded or validated.
UnsafeDataRootAncestor
A path-ambient store backend was configured beneath a renameable directory.
Fields
TransportBind
A transport listener could not bind or start.
Fields
address: SocketAddrConfigured listener address.
Transport
A running transport task aborted: it panicked or was cancelled.
Fields
SignalListener
A termination-signal listener could not be installed or failed.
Fields
DeathNote
The death note — the durable record of what killed the process — could not be armed at boot.
PidFile
The pid file or a control-verb record could not be written or read.
HomeAlreadyClaimed
A LIVE server incarnation already holds this Aion home on addresses that collide with the ones this boot intends to bind. Refusing is the whole point: two servers on one home do not share it — the second blocks silently inside the store’s writer lock — so this is an operator-facing refusal (exit 2), not a crash.
Fields
refusal: Box<HomeAlreadyClaimed>The refusal, carrying the live holder’s whole record so a caller
can render whatever the operator needs. Boxed to keep
ServerError small: every other variant is a handful of words.
Incarnation
This process’s own incarnation identity (process-table start instant, executable path, binary hash) could not be read.
Namespace
Namespace validation or authorization failed.
EngineCall
Engine call failed.
Fields
source: EngineErrorTyped engine error returned by the embedded engine.
StoreBackend
Store backend call failed before an engine handle was available.
Fields
source: StoreErrorTyped store error returned by the configured backend.
Stream
Streaming failure.
Fields
failure: StreamFailureStream failure class.
WorkerDispatch
A scheduled activity could not be pushed to a worker.
Fields
WorkerConnectionLost
The worker connection chosen for a dispatch was lost mid-flight: the connection was already gone at push time, or it closed before the worker sent its correlated push reply.
This is DISTINCT from Self::WorkerDispatch: a WorkerDispatch covers a
genuine reply timeout (the worker is alive but slow), a no-worker-available
selection failure, or any other dispatch fault, all of which keep the
outbox’s normal exponential backoff. A WorkerConnectionLost instead means
the chosen worker is gone (and has already been deregistered by liminal’s
on_worker_unregistered), so the row can be re-armed for IMMEDIATE re-claim
to fail over to a live worker without waiting out the backoff. The outbox
dispatcher keys its fast-failover decision on this variant.
Fields
WorkerBusy
The worker connection chosen for a dispatch refused admission because it already holds its pending-push cap — the worker is ALIVE and WORKING, its connection is simply full of held dispatches.
DISTINCT from both Self::WorkerDispatch (which consumes a retry
attempt on backoff) and Self::WorkerConnectionLost (immediate
attempt-consuming failover): a busy worker is neither slow to reply nor
gone, so the outbox re-arms the row ATTEMPT-NEUTRALLY after a short
backoff — capacity pressure must never spend the retry budget that
prices genuine delivery failures, and must never dead-letter work.
Fields
WorkerDispatchUnservable
The dispatch can never be delivered on this worker connection at this
bound, on this attempt or any later one: liminal proved the encoded
dispatch frame is larger than the connection’s WHOLE outbound buffer
(liminal_server::ServerError::PushFrameExceedsOutboundCapacity), so no
amount of draining, waiting or failover to an identically-bounded worker
can carry it.
DISTINCT from all three dispatch-failure classes above, and the
distinction is the fix: Self::WorkerConnectionLost fails over
immediately, Self::WorkerBusy parks attempt-neutrally, and
Self::WorkerDispatch retries on backoff. Each of those is the right
answer to a fault that can clear. This one cannot clear, and every retry
of it writes another lease and another copy of the oversize input into
durable history for a step that never ran (measured: 846 leases,
5.93 MiB, one activity). Both dispatch paths therefore settle it
TERMINALLY on the first observation: the outbox dead-letters the row, the
engine-seam bridge reports a terminal: outcome. The detail names the
frame’s size, the bound, and the operator key that sets the bound.
Fields
PendingActivityCollision
A second dispatcher tried to install a responder for an execution site whose prior attempt is still held live, and the incoming attempt does not supersede the holder.
A HIGHER attempt never reaches this error: it takes the site over (aion#195) — the fence already superseded the holder’s tokens when the higher attempt was issued, so the holder is a corpse whose completion would be refused anyway, and refusing the live retry on its account killed healthy runs. Only a same-or-lower attempt — a genuine double dispatch of work that may still be executing — is refused here.
Fields
workflow_id: WorkflowIdWorkflow whose responder slot is already occupied.
activity_id: ActivityIdActivity site whose responder slot is already occupied.
ActivityCompletionRejected
A worker result did not prove ownership of the current execution generation and was refused before reaching workflow state.
Fields
workflow_id: WorkflowIdWorkflow named by the submitted completion.
activity_id: ActivityIdActivity site named by the submitted completion.
reason: CompletionRejectionReasonTyped reason the completion token did not authorize this write.
DeclaredAttemptCollision
A second server-executed declared body was started for an execution site whose prior attempt is still running here.
Distinct from Self::PendingActivityCollision, which is about the
responder slot a dispatch installs: this is about the PROCESS. The
registry that makes a running declared command cancellable holds one
cancellation handle per attempt, so admitting a second execution would
replace the first command’s handle — and a replaced handle is a command
running on the operator’s machine that nothing can stop. Refusing the
second is the only outcome that leaves both attempts accounted for.
Fields
workflow_id: WorkflowIdWorkflow whose declared body is already executing.
activity_id: ActivityIdActivity site whose declared body is already executing.
DrainingRefusedDeclaredAttempt
A draining server refused to start a declared command.
The drain latch is the promise aion server stop makes to the
operator: no new work starts after the stop is requested. A declared
body executes at the server itself — no worker gate can refuse it —
so the registration that admits it to the cancel path is also the door
the drain closes. The dispatcher maps this refusal to the park
sentinel, exactly like a worker dispatch parked mid-drain: nothing is
recorded, and the next boot re-dispatches the attempt.
Fields
workflow_id: WorkflowIdWorkflow whose declared body was refused.
activity_id: ActivityIdActivity site whose declared body was refused.
LockPoisoned
A lock was poisoned and the protected state cannot be trusted.
Wire
A failure already translated into the public wire taxonomy.
Implementations§
Source§impl ServerError
impl ServerError
Sourcepub fn to_wire_error(&self) -> WireError
pub fn to_wire_error(&self) -> WireError
Convert a server error that crosses a transport boundary into the stable public wire taxonomy.
Sourcepub const fn is_config(&self) -> bool
pub const fn is_config(&self) -> bool
Return true when this is an operator configuration failure.
Sourcepub fn namespace_denied(message: impl Into<String>) -> Self
pub fn namespace_denied(message: impl Into<String>) -> Self
Construct a namespace-denied error without embedding authorization logic.
Sourcepub fn placement_admission_denied(
namespace: &str,
worker_node: Option<&str>,
required: &BTreeSet<String>,
) -> Self
pub fn placement_admission_denied( namespace: &str, worker_node: Option<&str>, required: &BTreeSet<String>, ) -> Self
Construct the loud, whole-registration rejection when a worker’s advertised
node violates a Pinned{L} namespace’s placement (Control-Plane Phase 2,
P2-I1). Names the offending namespace, the worker’s advertised node (or
“none”), and the required label set, so the operator sees exactly why the
registration was refused. Carried on the namespace-denied wire code — a
registration refused on isolation grounds is a namespace-authorization
failure, not a transient dispatch error.
Sourcepub fn deploy_denied(message: impl Into<String>) -> Self
pub fn deploy_denied(message: impl Into<String>) -> Self
Construct a deploy-authorization denial carried on the dedicated
deploy_denied wire code (deploy is not a namespace operation).
Sourcepub fn grant_denied(message: impl Into<String>) -> Self
pub fn grant_denied(message: impl Into<String>) -> Self
Construct a grant-authorization denial carried on the dedicated
grant_denied wire code.
Separate from Self::deploy_denied on purpose: deploy_denied
names the deploy surface, so spelling it for a caller refused on some
other grant word would send that caller — and the operator reading the
audit line — to a surface the request never touched. Built by
crate::namespace::grants::require_grant, which fills in the word
and the knob that carries it.
Sourcepub const fn lagged_stream() -> Self
pub const fn lagged_stream() -> Self
Construct a lagged-stream error.
Sourcepub fn worker_dispatch(
namespace: impl Into<String>,
activity_type: impl Into<String>,
reason: impl Into<String>,
) -> Self
pub fn worker_dispatch( namespace: impl Into<String>, activity_type: impl Into<String>, reason: impl Into<String>, ) -> Self
Construct a worker-dispatch error.
Sourcepub fn worker_connection_lost(
channel: impl Into<String>,
detail: impl Into<String>,
) -> Self
pub fn worker_connection_lost( channel: impl Into<String>, detail: impl Into<String>, ) -> Self
Construct a worker-connection-lost error for a dispatch whose chosen worker connection was gone at push time or closed before replying.
Sourcepub fn worker_dispatch_unservable(
channel: impl Into<String>,
detail: impl Into<String>,
) -> Self
pub fn worker_dispatch_unservable( channel: impl Into<String>, detail: impl Into<String>, ) -> Self
Construct an unservable-dispatch error for a frame liminal proved larger than the worker connection’s whole outbound buffer.
Sourcepub const fn is_worker_connection_lost(&self) -> bool
pub const fn is_worker_connection_lost(&self) -> bool
Return true when this is a lost-worker-connection dispatch failure.
The outbox dispatcher keys its fast cross-node failover on this: a lost connection means the worker is gone (already deregistered), so the row is re-armed for immediate re-claim instead of waiting out the retry backoff.
Sourcepub fn worker_busy(
channel: impl Into<String>,
detail: impl Into<String>,
) -> Self
pub fn worker_busy( channel: impl Into<String>, detail: impl Into<String>, ) -> Self
Construct a worker-busy error for a dispatch refused at push admission because the worker’s connection already holds its pending-push cap.
Sourcepub const fn is_worker_busy(&self) -> bool
pub const fn is_worker_busy(&self) -> bool
Return true when this is a busy-worker admission refusal.
The outbox dispatcher keys its ATTEMPT-NEUTRAL re-arm on this: a full connection means the worker is alive and holding earlier dispatches, so the row waits for capacity without spending the retry budget that prices genuine delivery failures.
Sourcepub const fn is_worker_dispatch_unservable(&self) -> bool
pub const fn is_worker_dispatch_unservable(&self) -> bool
Return true when this dispatch can never be delivered on its connection at the configured outbound bound, so no retry of it may ever be scheduled.
Both dispatch paths key their terminal settlement on this: the outbox dead-letters the row on the first observation, and the engine-seam bridge reports a non-retryable outcome.
Sourcepub const fn lock_poisoned(resource: &'static str) -> Self
pub const fn lock_poisoned(resource: &'static str) -> Self
Construct a lock-poison error at the lock boundary.
Source§impl ServerError
impl ServerError
Sourcepub fn trace_fields(&self) -> ErrorTraceFields<'_>
pub fn trace_fields(&self) -> ErrorTraceFields<'_>
Return stable typed fields for structured error logging.
Trait Implementations§
Source§impl Debug for ServerError
impl Debug for ServerError
Source§impl Display for ServerError
impl Display for ServerError
Source§impl Error for ServerError
impl Error for ServerError
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<EngineError> for ServerError
impl From<EngineError> for ServerError
Source§fn from(source: EngineError) -> Self
fn from(source: EngineError) -> Self
Source§impl From<StoreError> for ServerError
impl From<StoreError> for ServerError
Source§fn from(source: StoreError) -> Self
fn from(source: StoreError) -> Self
Auto Trait Implementations§
impl !RefUnwindSafe for ServerError
impl !UnwindSafe for ServerError
impl Freeze for ServerError
impl Send for ServerError
impl Sync for ServerError
impl Unpin for ServerError
impl UnsafeUnpin for ServerError
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> IntoMaybeUndefined<T> for T
impl<T> IntoMaybeUndefined<T> for T
Source§fn into_maybe_undefined(self) -> MaybeUndefined<T>
fn into_maybe_undefined(self) -> MaybeUndefined<T>
Source§impl<T> IntoOption<T> for T
impl<T> IntoOption<T> for T
Source§fn into_option(self) -> Option<T>
fn into_option(self) -> Option<T>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request