#[non_exhaustive]pub enum EngineError {
Show 13 variants
NotFound {
entity: &'static str,
},
Validation {
kind: ValidationKind,
detail: String,
},
Contention(ContentionKind),
Conflict(ConflictKind),
State(StateKind),
Bug(BugKind),
Transport {
backend: &'static str,
source: Box<dyn Error + Send + Sync + 'static>,
},
Unavailable {
op: &'static str,
},
ResourceExhausted {
pool: &'static str,
max: u32,
retry_after_ms: Option<u32>,
},
Timeout {
op: &'static str,
elapsed: Duration,
},
StreamDisconnected {
cursor: StreamCursor,
},
StreamBackpressure,
Contextual {
source: Box<EngineError>,
context: String,
},
}Expand description
Typed engine-error surface. See module docs.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
NotFound
A uniquely-identified resource did not exist. entity is a
stable label (e.g. "execution", "flow", "attempt") that
consumers can match without re-parsing a message.
Validation
Caller supplied a malformed, out-of-range, or otherwise
rejected input. detail carries the Lua-side payload (field
name, offending value, or CSV of missing tokens, depending on
kind).
Contention(ContentionKind)
Transient conflict with another worker or with the current state of the execution/flow. Caller should retry per RFC-010 §10.7.
Conflict(ConflictKind)
Permanent conflict — the requested mutation conflicts with an existing record (e.g. duplicate edge, cycle, already-in-flow). Caller must not blindly retry.
State(StateKind)
Legal but surprising state — lease expired, already-suspended,
duplicate-signal, budget-exceeded, etc. Per-variant semantics
documented on StateKind.
Bug(BugKind)
FF-internal invariant violation that should not be reachable in a correctly-behaving deployment. Consumers typically log and surface as a 5xx.
Transport
Backend transport fault or response-parse failure (RFC-012 §4.2
round-4 shape). Broadened in Stage 0 to carry Box<dyn Error>
so non-Valkey backends (Postgres, future) can route their
native transport errors through this variant without going via
ScriptError.
backend— static diagnostic label ("valkey","postgres", etc.). Kept&'static strto avoid heap alloc on construction.source— boxed error. For the Valkey backend this isff_script::error::ScriptError; downcast withsource.downcast_ref::<ScriptError>()to recoverferriskey::ErrorKind/ parse detail. Helper lives inff_script::engine_error_ext::transport_script_ref.
Backend method not wired up yet (RFC-012 §4.2 K#7 holdover).
Returned by staged backend impls for methods that are known
types in the trait but not yet implemented. Graceful degradation
in place of unimplemented!() panics. Additive; does not
participate in the From<ScriptError> mapping.
ResourceExhausted
Backend-owned concurrency pool reached its ceiling (RFC-017 §6).
pool is a stable label ("stream_ops", "admin_rotate", …);
max is the pool ceiling; retry_after_ms, when set, is an
advisory retry hint the backend computed from its own back-
pressure signal. Maps to HTTP 429 at the ff-server boundary.
Timeout
An operation ran past its deadline (RFC-017 §5.4
shutdown_prepare). op is a stable label, elapsed is how
long the operation ran before the caller aborted. Additive;
call sites that previously did not emit this variant keep
emitting whatever they emitted before.
StreamDisconnected
RFC-019 Stage A — a subscription stream returned by
crate::engine_backend::EngineBackend::subscribe_lease_history
(or its siblings) observed a backend disconnect. The cursor is
the last event position the stream successfully yielded (or
crate::stream_subscribe::StreamCursor::empty if none was
observed). Consumers reconnect by re-calling the same
subscribe_* method with this cursor — that is the
owner-adjudicated disconnect contract (RFC-019 §Open
Questions #2).
Terminal from the stream’s perspective: the subscription ends after yielding this error.
Fields
cursor: StreamCursorStreamBackpressure
RFC-019 Stage A — a subscription stream fell behind its bounded
queue and dropped events rather than blocking the producer.
Reserved for backends that explicitly surface lag (Stage B
lands the first call-site via subscribe_instance_tags); no
Stage A backend emits this today but consumers match on it to
future-proof reconciliation paths.
Non-terminal: the stream continues after this error; callers treat it as a “refresh from authoritative state” signal.
Contextual
An inner EngineError wrapped with a call-site label so
operators triaging logs can see which op the error came from
without inferring from surrounding spans. Constructed via
backend_context; carries a lightweight string context
(e.g. "renew: FCALL ff_renew_lease").
Classification helpers (ErrorClass, BackendErrorKind,
etc.) transparently descend into source so a consumer that
matches on the wrapper arm keeps the same retry/terminal
semantics as the unwrapped inner error.
Implementations§
Source§impl EngineError
impl EngineError
Sourcepub fn class(&self) -> ErrorClass
pub fn class(&self) -> ErrorClass
Classify an EngineError using the underlying
ErrorClass table.
Transport classification in ff-core: the inner source is
Box<dyn std::error::Error> which ff-core cannot downcast
without naming ScriptError. ff-core returns Terminal for
every Transport variant by default. Callers needing the
Retryable-on-transient-Valkey-error classification use
ff_script::engine_error_ext::class which downcasts to
ScriptError and delegates to ScriptError::class. ff-sdk’s
public SdkError::is_retryable / backend_kind methods wire
the ff-script helper in so consumers retain the Phase-1
behavior transparently. (backend_kind was renamed from
valkey_kind in #88.)
Trait Implementations§
Source§impl Debug for EngineError
impl Debug for EngineError
Source§impl Display for EngineError
impl Display for EngineError
Source§impl Error for EngineError
impl Error for EngineError
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()