nautechsystems/nautilus_trader · error · anyhow::Error
Unknown execution event marker {event}
Error message
Unknown execution event marker {event} What it means
`mark_execution_event_emitted` persists that an order event was dispatched so it is not re-emitted after restart; it recognizes exactly three event markers — 'acknowledgement', 'fill', 'terminal' — each mapped to a guarded UPDATE. Any other string hits the catch-all bail. A second ensure in the same method also fails when the intent row is absent or the opposing marker gate rejects the update.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:3893
///
/// Returns an error if the event kind is unknown, the intent is absent, the opposing
/// terminal marker is already set, or persistence fails.
pub async fn mark_execution_event_emitted(
&self,
intent_id: i64,
event: &str,
) -> anyhow::Result<()> {
let statement = match event {
"acknowledgement" => {
"UPDATE execution_intent SET acknowledgement_emitted = TRUE, updated_at = NOW() WHERE id = $1"
}
"fill" => {
"UPDATE execution_intent SET fill_emitted = TRUE, active = CASE WHEN status = 'finalized' THEN FALSE ELSE active END, updated_at = NOW() WHERE id = $1 AND NOT terminal_emitted"
}
"terminal" => {
"UPDATE execution_intent SET terminal_emitted = TRUE, active = CASE WHEN status IN ('finalized', 'reverted') THEN FALSE ELSE active END, updated_at = NOW() WHERE id = $1 AND NOT fill_emitted"
}
_ => anyhow::bail!("Unknown execution event marker {event}"),
};
let result = sqlx::query(statement)
.bind(intent_id)
.execute(&self.pool)
.await
.map_err(|e| anyhow::anyhow!("Failed to mark execution {event} emitted: {e}"))?;
anyhow::ensure!(
result.rows_affected() == 1,
"Execution intent {intent_id} cannot mark {event} emitted"
);
Ok(())
}
/// Updates the status of a persisted execution transaction record.
///
/// # Errors
///
/// Returns an error if the database operation fails.View on GitHub (pinned to 2114cf6f76)
Solutions
- Use exactly one of the lowercase literals: 'acknowledgement', 'fill', 'terminal'.
- Better: model the kind as an enum and convert to the string at the boundary so invalid values fail to compile.
- If the value arrives from config or a queue, validate it against the allowed set before the call.
- If the string looks correct, check the follow-on ensure ('cannot mark {event} emitted') — that indicates a missing intent row or an opposing-marker conflict, not an unknown marker.
Example fix
// before
executor.database.mark_execution_event_emitted(intent_id, 'Fill').await?; // bails: unknown marker
// after: type-safe marker
#[derive(Clone, Copy)]
enum ExecutionEventMarker { Acknowledgement, Fill, Terminal }
impl ExecutionEventMarker {
fn as_str(self) -> &'static str {
match self { Self::Acknowledgement => 'acknowledgement', Self::Fill => 'fill', Self::Terminal => 'terminal' }
}
}
executor.database.mark_execution_event_emitted(intent_id, ExecutionEventMarker::Fill.as_str()).await?; Defensive patterns
Strategy: type-guard
Validate before calling
const MARKERS: &[&str] = &['acknowledgement', 'fill', 'terminal'];
anyhow::ensure!(MARKERS.contains(&event), 'event must be one of {MARKERS:?}, got {event}'); Type guard
#[derive(Clone, Copy)]
enum ExecutionEventMarker { Acknowledgement, Fill, Terminal }
impl ExecutionEventMarker {
fn as_str(self) -> &'static str {
match self {
Self::Acknowledgement => 'acknowledgement',
Self::Fill => 'fill',
Self::Terminal => 'terminal',
}
}
}
// only ever pass marker.as_str(); invalid kinds cannot be expressed Try / catch
Match the error: if the message starts with 'Unknown execution event marker', fix the caller's string (exact lowercase literal) — retrying with the same value will always fail. A 'cannot mark ... emitted' message instead means a missing intent row or opposing-marker conflict.
Prevention
- Do not call this internal API with free-form strings; wrap it behind an enum.
- Keep event vocabulary in one shared constant list.
- Add a unit test over all call sites' event literals.
When it happens
Trigger: Calling the method with a string other than the three exact literals: 'Fill' (wrong case), 'reject', 'ack', a trailing space, or a newly introduced event kind the running build does not know.
Common situations: Custom tooling calling this internal database API directly; refactors that rename event kinds without updating call sites; version mixing where a caller emits a newer event vocabulary than the database layer understands.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Execution schema version {} is newer than supported version
- Blockchain execution transaction limits are required: allowe
- `slippage_bps` {slippage_bps} exceeds `max_slippage_bps` {ma
- Finalized block {} does not contain transaction {}
- in-flight mutex poisoned
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/c95f96993393ede2.
Report an issue: GitHub.