#[non_exhaustive]pub enum SnapshotError {
Show 21 variants
MapNotFound {
requested: String,
available: Vec<String>,
},
VarNotFound {
requested: String,
available: Vec<String>,
},
AmbiguousVar {
requested: String,
found_in: Vec<String>,
},
FieldNotFound {
requested: String,
walked: String,
component: String,
available: Vec<String>,
},
NotAStruct {
requested: String,
walked: String,
component: String,
kind: String,
},
TypeMismatch {
expected: String,
actual: String,
requested: String,
},
IndexOutOfRange {
map: String,
index: usize,
len: usize,
},
PerCpuSlot {
map: String,
cpu: u32,
len: usize,
unmapped: bool,
},
NoMatch {
map: String,
op: String,
len: usize,
available_keys: Vec<String>,
},
EmptyPathComponent {
requested: String,
},
PerCpuNotNarrowed {
map: String,
},
NoRendered {
map: String,
side: String,
},
PlaceholderSample {
tag: String,
reason: String,
},
MissingStats {
tag: String,
reason: MissingStatsReason,
},
HostFieldUnavailable {
tag: String,
cpu: u32,
},
PlaceholderSnapshot {
tag: Option<String>,
},
NoActiveScheduler {
reason: String,
},
ActiveFilterExcludedMaps {
requested: String,
active_obj: String,
excluded_maps: Vec<ExcludedMap>,
whitelist_kvas: Vec<u64>,
},
WalkerDriftedWithinPhase {
phase: Phase,
pinned_kvas: Vec<u64>,
sample_kvas: Vec<u64>,
requested: String,
},
ProjectionFailed {
reason: String,
},
MapRenderIncomplete {
map: String,
error: String,
},
}Expand description
Reason a snapshot accessor or terminal read could not resolve.
Returned by every fallible accessor (Snapshot::map,
SnapshotEntry::get, SnapshotField::as_u64, …) so a missing
field, type mismatch, or absent map surfaces as a structured
error the test author can ?-propagate. Each variant carries
the path / alternatives needed to fix the call site without
re-running the test.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
MapNotFound
No map matched the requested name. available enumerates
the captured map names so a typo surfaces in test output.
VarNotFound
No top-level global variable matched the requested name in
any *.bss / *.data / *.rodata global-section map.
available lists the union of every section’s top-level
member names.
AmbiguousVar
More than one global-section map exposes a top-level member
with the requested name, so super::Snapshot::var cannot pick a
deterministic answer. found_in lists every map (in capture
order) where the name was seen — the caller should disambiguate
via super::Snapshot::map and walk into the named map directly
(e.g. snap.map("scx_obj.bss")?.at(0).get("nr_cpus")).
FieldNotFound
A path component did not match any
crate::monitor::btf_render::RenderedValue::Struct member at that depth. requested
is the user-supplied lookup string; walked is the prefix
that resolved successfully; component is the failing
segment; available lists the struct’s actual member names.
NotAStruct
A path component reached a non-Struct value where a struct
was expected (e.g. descending into a Uint leaf).
requested is the user-supplied lookup string; kind names
the actual variant for diagnostics.
TypeMismatch
A typed accessor (as_u64 etc.) was called on a rendered
shape it cannot decode (e.g. as_str on a Struct).
expected names the scalar type the accessor requires;
actual names the rendered variant; requested is the
user-supplied lookup string (empty when the accessor was
invoked on a leaf without a path walk).
IndexOutOfRange
A map index was out of range for the underlying entry list.
PerCpuSlot
A per-CPU slot was out of range or unmapped.
NoMatch
A predicate-based lookup (find, max_by) found no match.
len is the number of entries the lookup traversed before
giving up; available_keys is a small sample (up to
NO_MATCH_KEY_SAMPLE entries) of rendered keys seen during
the traversal so an operator can distinguish “empty map”
(len == 0) from “populated map with no predicate hit”
(len > 0) and inspect the sample to debug the predicate.
Keys are rendered via crate::monitor::btf_render::RenderedValue’s Display impl and
each is capped at NO_MATCH_KEY_CHAR_CAP chars with an
ellipsis to keep the failure message readable for wide struct
keys.
Aggregation methods (max_by, cpu_max_u64 / cpu_min_u64
/ cpu_max_f64 / cpu_min_f64) produce this variant for
empty / all-None inputs; their NoMatch always carries
len == 0 and empty available_keys. Only find can
produce len > 0 here.
EmptyPathComponent
A path string contained an empty component (e.g. "a..b").
requested is the user-supplied lookup string.
PerCpuNotNarrowed
super::SnapshotEntry::get was called on a per-CPU entry
without narrowing to a CPU first via super::SnapshotMap::cpu.
NoRendered
Hash entry has no rendered key/value side (BTF type id was missing at capture time, leaving the hex bytes only).
PlaceholderSample
The sample’s underlying crate::monitor::dump::FailureDumpReport
is a placeholder produced by
crate::monitor::dump::FailureDumpReport::placeholder —
the freeze-rendezvous path could not collect real data
(typical cause: vCPU rendezvous timed out). Temporal
patterns in crate::assert::temporal route this variant
through their per-sample skip handling so a placeholder
sample never falsely registers as zero progress against a
monotonicity / rate / steady / ratio band. The reason
string mirrors FailureDumpReport::scx_walker_unavailable
when present (set by placeholder() to the constructor
argument), giving the operator the cause without re-walking
the report.
MissingStats
A SampleSeries::stats
projection ran on a sample whose stats field carries an
Err — the stats client was not wired (no
scheduler_binary) or the per-sample stats request failed.
The carried MissingStatsReason identifies the why so
operator diagnostics distinguish “no scheduler configured”
from “scheduler refused the request” from “watchdog
cancelled the request” without re-walking the source error.
Distinguishes a per-sample stats coverage gap from an
in-stats-JSON path miss (TypeMismatch /
FieldNotFound) so the temporal-assertion site can
branch on the cause without re-walking the source.
A SampleSeries::host
projection ran on a sample whose per_cpu_time slice did
not include cpu — placeholder report (freeze rendezvous
timed out), or a kernel that didn’t surface per-CPU
kernel_stat/tick_cpu_sched/kernel_cpustat resolution
for the requested CPU. Distinguishes a per-sample host-data
coverage gap from a kernel-walker failure (Unavailable on
the broader Snapshot accessor) so the temporal-assertion
site can decide whether to fail strict or skip with a
rendered Note.
PlaceholderSnapshot
super::Snapshot::var / super::Snapshot::live_var /
super::Snapshot::map was called on a snapshot whose
underlying crate::monitor::dump::FailureDumpReport is a
placeholder (the freeze-rendezvous path could not collect
real data — typical cause: vCPU rendezvous timed out). The
captured report.maps is empty by construction so the
var/map lookup has nothing to walk. Distinct from
Self::VarNotFound (which means “the captured report did
not contain a global by this name”) so the assertion site
can distinguish “freeze failed” from “typo in field name”.
tag carries the capture tag (if any).
NoActiveScheduler
super::Snapshot::active / super::Snapshot::live_var
could not identify a currently-active scheduler from the
snapshot’s *scx_root + prog_runtime_stats. Typical
causes: snapshot taken in the dead window between
crate::scenario::ops::Op::DetachScheduler +
crate::scenario::ops::Op::AttachScheduler; snapshot
taken in the post-swap settle window before the new
scheduler’s progs have advanced their run counter; snapshot
captured before any scheduler attached. Distinct from
Self::AmbiguousVar (which means “the snapshot has
multiple scheduler bss copies and the call did not opt
into active-only filtering”) so the assertion site can
distinguish “no scheduler is running right now” from
“multiple are running, pick one”.
ActiveFilterExcludedMaps
super::Snapshot::var / super::Snapshot::map (or one
of the live_* shortcuts) ran against an active-filtered
view where the KVA whitelist excluded EVERY captured map
that shared the active obj prefix (i.e. the admitted set
for this obj was empty). Distinct from Self::VarNotFound
— VarNotFound means “the active filter admitted maps but
none carry the requested name”; this variant means “the
active filter admitted zero maps for this obj, so the
lookup never got the chance to walk anything.”
The variant never fires when at least one captured
<active_obj>.* map passes the KVA whitelist — in that
case the lookup miss is a real typo or absent symbol and
the standard VarNotFound / MapNotFound carries the
admitted list. This narrow firing scope prevents
false-positives that would otherwise mask genuine typos
in same-binary post-swap captures.
Typical causes when this DOES fire: stale walker capture
(captured KVAs predate the most recent struct_ops swap),
same-binary post-swap window where the report still
carries the old instance’s maps, or a walker bug that
resolved *scx_root against a different binary’s map set.
Fields
requested: StringUser-supplied lookup string (the var / map
argument). For super::Snapshot::live_vars_via this
carries the joined name list "[a, b, c]".
active_obj: StringObj name the active filter pinned to
(*scx_root → struct_ops map → obj prefix resolution).
excluded_maps: Vec<ExcludedMap>Maps captured under the active obj prefix that the KVA whitelist rejected.
WalkerDriftedWithinPhase
A walker-resolved crate::scenario::sample::SampleSeries::bpf_live_u64
/ bpf_live_i64 / bpf_live_f64 projection detected that
the snapshot’s per-snapshot walker output
(crate::monitor::dump::FailureDumpReport::active_map_kvas)
disagrees with an earlier same-phase snapshot’s walker
output for the same lookup. The framework pins the first
non-empty walker output it sees per phase and surfaces this
variant for every later same-phase snapshot whose walker
resolved to a different KVA set — without this gate the
projected series would silently switch between bss copies
mid-phase (typical cause: post-Op::ReplaceScheduler swap
window where the walker re-publishes mid-phase) and
downstream reducers like
crate::assert::temporal::SeriesField::counter_delta_per_phase
would see non-monotonic counter values. The drifted
samples become per-sample Err slots; the temporal
patterns’ standard error-skip semantics apply.
ProjectionFailed
A user-supplied projection closure (the kind passed to
crate::scenario::sample::SampleSeries::bpf) signalled
failure for reasons that don’t fit the structured variants
above. reason is the closure’s free-form explanation —
“lookup returned None for sched_id A, B, C” — so the failure
message stays diagnostic without forcing the closure to
synthesize an available: Vec<String> it cannot populate.
Closures should reach for the structured variants
(Self::VarNotFound, Self::MapNotFound, etc.) when
they can; this variant is the escape hatch for higher-level
disambiguation logic (e.g. “I walked vars(name) and none of
the candidates matched my active-instance fingerprint”).
Surfaces in temporal-assertion failure messages as
projection failed: <reason>.
MapRenderIncomplete
A captured map’s contents could not be rendered at dump time:
crate::monitor::dump::FailureDumpMap::error is set and the
map carries no entries / value to walk. Surfaced by
super::Snapshot::var / super::SnapshotMap::at /
super::SnapshotMap::find / super::SnapshotMap::max_by
instead of Self::VarNotFound /
Self::IndexOutOfRange { len: 0 } /
Self::NoMatch { len: 0 } so a guest-memory render
failure is distinguishable from a genuinely-absent variable
or a legitimately-empty map. Without this distinction a map
whose contents failed to read reads identically to “the
symbol does not exist”, masking the capture failure.
map names the owning map; error mirrors
FailureDumpMap.error.
Trait Implementations§
Source§impl Clone for SnapshotError
impl Clone for SnapshotError
Source§fn clone(&self) -> SnapshotError
fn clone(&self) -> SnapshotError
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for SnapshotError
impl Debug for SnapshotError
Source§impl<'de> Deserialize<'de> for SnapshotError
impl<'de> Deserialize<'de> for SnapshotError
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl Display for SnapshotError
impl Display for SnapshotError
Source§impl Error for SnapshotError
impl Error for SnapshotError
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
Source§impl Hash for SnapshotError
impl Hash for SnapshotError
Source§impl PartialEq for SnapshotError
impl PartialEq for SnapshotError
Source§impl Serialize for SnapshotError
impl Serialize for SnapshotError
impl Eq for SnapshotError
impl StructuralPartialEq for SnapshotError
Auto Trait Implementations§
impl Freeze for SnapshotError
impl RefUnwindSafe for SnapshotError
impl Send for SnapshotError
impl Sync for SnapshotError
impl Unpin for SnapshotError
impl UnwindSafe for SnapshotError
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<T> ErrorExt for T
impl<T> ErrorExt for T
§fn and_raise<T>(self, context: T) -> Exn<T>
fn and_raise<T>(self, context: T) -> Exn<T>
§fn raise_erased(self) -> Exnwhere
Self: Sized,
fn raise_erased(self) -> Exnwhere
Self: Sized,
§fn raise_all<T, I>(self, sources: I) -> Exn<Self>where
Self: Sized,
T: Error + Send + Sync + 'static,
I: IntoIterator,
<I as IntoIterator>::Item: Into<Exn<T>>,
fn raise_all<T, I>(self, sources: I) -> Exn<Self>where
Self: Sized,
T: Error + Send + Sync + 'static,
I: IntoIterator,
<I as IntoIterator>::Item: Into<Exn<T>>,
sources as causes.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§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