Skip to main content

ValidationError

Enum ValidationError 

Source
pub enum ValidationError {
Show 36 variants InvalidRunAnnotation { message: String, }, ClusterRepoNamespaceForbidden { namespace: String, }, ConsumerNamespaceNotAllowed { namespace: String, repo: String, }, DiscoveredMustRetain { got: String, }, DiscoveredCannotSetOnScheduleDelete { origin: &'static str, got: String, }, RestoreSourceRepositoryRequired, InlineRetentionForbidden { field: String, }, InvalidCron { expr: String, reason: String, }, InvalidTimezone { name: String, }, MutuallyExclusive { a: String, b: String, context: String, }, MissingRequiredField { field: String, }, InvalidFieldValue { field: String, reason: String, }, IdentityExprCompile { expr: String, reason: String, }, IdentityExprEval { expr: String, reason: String, }, IdentityExprType { expr: String, got: String, }, InsecureServerNotAcknowledged, InvalidServerPort { port: u16, }, ServerNamespaceRequired, SelectorLabelsUnavailable { namespace: String, repo: String, }, Immutable { field: String, }, IdentityCollision { identity: String, conflict: String, }, IdentityComponentInvalid { field: String, value: String, reason: String, }, IdentitySourcePathInvalid { field: String, value: String, reason: String, }, ClusterNameInvalid { value: String, reason: String, }, IdentityWouldFork { old: String, new: String, }, RepositoryIdentityWouldFork { consumers: Vec<String>, }, SuccessExprCompile { expr: String, reason: String, }, SuccessExprEval { expr: String, reason: String, }, SuccessExprType { expr: String, got: String, }, PreflightExprCompile { expr: String, reason: String, }, PreflightExprEval { expr: String, reason: String, }, PreflightExprType { expr: String, got: String, }, ReplicationDestinationSameAsSource { backend: String, }, MaintenanceNamespaceOnNamespacedRepo { namespace: String, }, ForeignSnapshotsRequiresCluster, ForeignSnapshotsChoiceRequired,
}
Expand description

A single cross-field validation failure. PartialEq so tests can assert the exact variant; messages are written for an end user reading a rejected apply.

Variants§

§

InvalidRunAnnotation

The maintenance run-requested/run-mode annotations are malformed (message produced by crate::maintenance::parse_run_annotations, already what/why/fix).

Fields

§message: String

The shared parser’s actionable message.

§

ClusterRepoNamespaceForbidden

A Repository/ClusterRepository’s own credential refs, or a consumer’s repository.namespace, set a namespace that the variant forbids. For kind: ClusterRepository, repository.namespace MUST be absent (ADR §3.2/§3.3) — the reference is cluster-scoped by name alone.

Fields

§namespace: String

The forbidden namespace that was set on the reference.

§

ConsumerNamespaceNotAllowed

A consumer namespace is not permitted by the target ClusterRepository’s allowedNamespaces tenancy gate (ADR §3.2/§4.3).

Fields

§namespace: String

The consumer namespace that was denied.

§repo: String

The ClusterRepository whose tenancy gate denied it.

§

DiscoveredMustRetain

A Snapshot with origin: discovered tried to set a deletionPolicy other than Retain. Discovered snapshots are forced Retain so the operator never deletes data it did not create (ADR §4.5).

Fields

§got: String

The rejected deletionPolicy that was set (anything but Retain).

§

DiscoveredCannotSetOnScheduleDelete

A Snapshot with origin: discovered or origin: adopted set spec.onScheduleDelete. Neither has an owning SnapshotSchedule for the field to apply to: a discovered snapshot’s owner is a repository, and an adopted snapshot’s owner is the SnapshotPolicy it was re-attached to — a stamped cascade policy on either is meaningless, so it is forbidden, exactly like a non-Retain deletionPolicy (Self::DiscoveredMustRetain).

Fields

§origin: &'static str

The origin that forbids the field ("discovered" or "adopted").

§got: String

The rejected onScheduleDelete value that was set.

§

RestoreSourceRepositoryRequired

A Restore with source.identity did not set spec.repository. Identity sources cannot derive a repository, so it is required (ADR §3.6/§4.6).

§

InlineRetentionForbidden

A Repository/ClusterRepository spec carried kopia-side (repo-level) retention policy fields, which conflict with CR-driven GFS retention and risk double-deletion (ADR §4.4 exclusivity).

Fields

§field: String

The offending repo-level retention field that was set.

§

InvalidCron

A cron expression failed to parse with the same parser the controller uses at runtime, so it is rejected at apply time rather than at first reconcile (ADR §4.1).

Fields

§expr: String

The cron expression that failed to parse.

§reason: String

The parser’s reason for rejecting it.

§

InvalidTimezone

A schedule’s timezone is not a recognized IANA timezone name (e.g. a typo like America/Chicgo), rejected at apply time rather than silently falling back to UTC at reconcile.

Fields

§name: String

The timezone string that failed to parse.

§

MutuallyExclusive

Two fields that may not both be set were both set (e.g. a Source with both pvc and pvcSelector).

Fields

§a: String

The first of the two conflicting fields.

§b: String

The second of the two conflicting fields.

§context: String

Where the conflict occurred (e.g. "snapshot source"), for the message.

§

MissingRequiredField

A required field (or “at least one of” surface) was empty.

Fields

§field: String

The required field (or “at least one of” surface) that was empty.

§

InvalidFieldValue

A field was set but its value is malformed (e.g. an NFS export path that is not absolute). The schema can’t express the constraint, so the webhook does.

Fields

§field: String

The offending field (e.g. "snapshot source nfs.path").

§reason: String

What’s wrong and how to fix it (e.g. "must be an absolute path").

§

IdentityExprCompile

A Repository/ClusterRepository identityDefaults CEL expression (hostnameExpr / usernameExpr) failed to compile (a syntax error, or it exceeds the length budget). Surfaced at admission so a bad expression never reaches status (ADR-0004 §5).

Fields

§expr: String

The offending CEL expression.

§reason: String

The parser’s reason (or the length-budget message).

§

IdentityExprEval

A Repository/ClusterRepository identityDefaults CEL expression referenced a variable outside its environment (e.g. a typo), or otherwise failed to evaluate at admission (ADR-0004 §5). The environment is namespace, policyName, labels, annotations, cluster.

Fields

§expr: String

The offending CEL expression.

§reason: String

The evaluation error (e.g. an undeclared-variable reference).

§

IdentityExprType

A Repository/ClusterRepository identityDefaults CEL expression evaluated to a non-string value. hostnameExpr/usernameExpr must return a string (ADR-0004 §5).

Fields

§expr: String

The offending CEL expression.

§got: String

The CEL value type it returned instead of a string.

§

InsecureServerNotAcknowledged

spec.server.auth.insecure was selected without acknowledgeInsecure: true. The no-auth server exposes full read/write/delete of the repository with no login, so it must be explicitly acknowledged (server addendum).

§

InvalidServerPort

spec.server.service.port was set to an invalid value (0).

Fields

§port: u16

The rejected port value (always 0 today).

§

ServerNamespaceRequired

A ClusterRepository.spec.server did not set the required target namespace.

§

SelectorLabelsUnavailable

A label selector was supplied as the tenancy gate but the caller could not provide the consumer namespace’s labels to match against. We fail closed (deny) rather than guess (ADR §3.2 — the webhook never trusts unfiltered input).

Fields

§namespace: String

The consumer namespace whose labels could not be evaluated.

§repo: String

The ClusterRepository gating by label selector.

§

Immutable

An UPDATE changed a repository field that is fixed at repository-creation time (encryption, create.splitter, create.hash, create.encryption). Kopia bakes these into the repository’s on-disk format, so they cannot change after creation — the webhook rejects the edit rather than silently ignoring it (ADR-0005 §7).

Fields

§field: String

The immutable field that an UPDATE attempted to change.

§

IdentityCollision

A SnapshotPolicy’s resolved kopia identity (username@hostname[:path]) collides with an already-admitted SnapshotPolicy’s identity in the same repository. Two recipes interleaving snapshots into one kopia identity corrupts the snapshot history, so the webhook rejects the second one (ADR-0005 §6).

Fields

§identity: String

The resolved username@hostname[:path] identity that collided.

§conflict: String

namespace/name of the already-admitted conflicting SnapshotPolicy.

§

IdentityComponentInvalid

A kopia identity component (username or hostname) — whether an explicit spec.identity override or the value an identityDefaults CEL expression resolved to — contains a character that breaks kopia’s username@hostname:path contract. kopia parses a source on the first @ and first : with no escaping, so an embedded @, :, ASCII whitespace, or control character silently misparses the identity into a different one (or makes the snapshot un-findable on snapshot list --source). Rejected at admission/resolution so it never reaches a mover Job. Shape-only — every other character (dots, dashes, slashes, unicode letters) is allowed.

Fields

§field: String

The offending field (e.g. "spec.identity.username" or "resolved hostname").

§value: String

The rejected value.

§reason: String

What’s wrong (e.g. "must not contain ':'").

§

IdentitySourcePathInvalid

A kopia identity sourcePath is malformed — empty, or it contains a newline or an ASCII control character. The path is everything after the first : in username@hostname:path; it may legitimately contain spaces and further :, but not control characters, and must be non-empty when set.

Fields

§field: String

The offending field (e.g. "spec.sources[0].sourcePathOverride").

§value: String

The rejected value.

§reason: String

What’s wrong and how to fix it.

§

ClusterNameInvalid

A Repository/ClusterRepository identityDefaults.cluster is not a valid RFC 1123 label, or contains a .. cluster is appended onto the namespace as <namespace>.<cluster> for the default hostname, and crate::identity::classify_hostname splits that hostname back apart at the FIRST . — a cluster value with an embedded dot would just shift which suffix classifies as “own cluster” rather than error, so the value is rejected outright at admission instead of letting classification silently disagree with intent.

Fields

§value: String

The rejected cluster name.

§reason: String

What’s wrong and how to fix it (e.g. the RFC 1123 shape, or the dot-as-delimiter rule).

§

IdentityWouldFork

An UPDATE to a SnapshotPolicy would change its resolved kopia identity (username@hostname, or a source’s path) while the policy already has snapshot history. New snapshots would land under the new kopia source: Kopiur’s own GFS retention pools ALL of a policy’s Snapshot CRs regardless of identity, so the old and new lineages don’t get independent retention — they compete for the same keepLatest/keepDaily/etc. buckets in one merged timeline, and restore/verify/ fromPolicy resolve only the new identity (the old lineage stays reachable via Restore.source.identity). Rejected unless the change is acknowledged with the kopiur.home-operations.com/allow-identity-change annotation (crate::consts::ALLOW_IDENTITY_CHANGE_ANNOTATION).

Fields

§old: String

The previously-pinned identity (or source path).

§new: String

The new identity (or source path) this edit would resolve to.

§

RepositoryIdentityWouldFork

An UPDATE to a Repository/ClusterRepository’s identityDefaults (cluster, hostnameExpr, or usernameExpr) would silently re-identify every consumer SnapshotPolicy that resolves through those defaults — identity is re-resolved from the LIVE repository on every reconcile/backup (nothing about a repository’s defaults is pinned the way a policy’s own spec.identity is), so this edit changes what each affected policy resolves to on its very next backup with no per-policy edit to acknowledge it. Exactly like Self::IdentityWouldFork, new snapshots would land under a new kopia lineage while the old lineage’s Snapshot CRs keep competing with it in the same merged GFS retention timeline (Kopiur pools a policy’s CRs regardless of identity, so nothing is independently retained) — but here it happens fleet-wide in one apply. Rejected unless the repository carries the kopiur.home-operations.com/allow-identity-change annotation (crate::consts::ALLOW_IDENTITY_CHANGE_ANNOTATION).

Fields

§consumers: Vec<String>

namespace/name of every consumer SnapshotPolicy with existing snapshot history that this edit would re-identify (the message truncates the rendered list to 5 names; this field carries all of them).

§

SuccessExprCompile

A verification successExpr (ADR-0005 §4/§15) failed to compile (a syntax error, or it exceeds the length budget). Surfaced at admission.

Fields

§expr: String

The offending CEL expression.

§reason: String

The parser’s reason (or the length-budget message).

§

SuccessExprEval

A verification successExpr referenced a variable outside its environment (e.g. a typo), or otherwise failed to evaluate (ADR-0005 §4/§15). The environment is stats{files,bytes,errors}, snapshot, restored.

Fields

§expr: String

The offending CEL expression.

§reason: String

The evaluation error (e.g. an undeclared-variable reference).

§

SuccessExprType

A verification successExpr evaluated to a non-bool value. A successExpr is a pass/fail predicate and must return a bool (ADR-0005 §4/§15).

Fields

§expr: String

The offending CEL expression.

§got: String

The CEL value type it returned instead of a bool.

§

PreflightExprCompile

A SnapshotPolicy.spec.preflight check expression failed to compile (CEL syntax error, or it exceeds the length budget). Surfaced at admission.

Fields

§expr: String

The offending CEL expression.

§reason: String

The parser’s reason (or the length-budget message).

§

PreflightExprEval

A preflight check expression referenced a variable outside its environment (e.g. a typo), or otherwise failed to evaluate. The environment is the repository and maintenance maps.

Fields

§expr: String

The offending CEL expression.

§reason: String

The evaluation error (e.g. an undeclared-variable reference).

§

PreflightExprType

A preflight check expression evaluated to a non-bool value. A preflight check is a pass/fail predicate and must return a bool.

Fields

§expr: String

The offending CEL expression.

§got: String

The CEL value type it returned instead of a bool.

§

ReplicationDestinationSameAsSource

A RepositoryReplication’s destination backend is identical to its source repository’s backend (ADR-0005 §13(d)) — replicating a repository to itself is a no-op (or worse, a loop). The webhook rejects it.

Fields

§backend: String

The backend kind that both source and destination resolved to.

§

MaintenanceNamespaceOnNamespacedRepo

A namespaced Repository set spec.maintenance.namespace, which only applies to a cluster-scoped ClusterRepository (a namespaced Repository’s managed Maintenance always lives in the repository’s own namespace). ADR §3.7.

Fields

§namespace: String

The spec.maintenance.namespace value set on the namespaced Repository.

§

ForeignSnapshotsRequiresCluster

catalog.foreignSnapshots is set, but there is no cluster identity to classify a snapshot’s origin against — Ignore/Fallback decide what to do with a snapshot crate::identity::classify_hostname classifies as another cluster’s, and that classification is undecidable without identityDefaults.cluster. Fires on either repository kind (Repository or ClusterRepository) whose identityDefaults.cluster is unset — kind-neutral wording, since the rule is identical either way.

§

ForeignSnapshotsChoiceRequired

A ClusterRepository sets both identityDefaults.cluster and catalog.fallbackNamespace but leaves catalog.foreignSnapshots unset. Both being set at once is a strong signal the fallback collector is actually relied upon, so adopting a cluster identity must never silently switch it off by defaulting to Ignore — the choice is forced explicit instead.

Trait Implementations§

Source§

impl Clone for ValidationError

Source§

fn clone(&self) -> ValidationError

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ValidationError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ValidationError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ValidationError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for ValidationError

Source§

fn eq(&self, other: &ValidationError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for ValidationError

Source§

impl StructuralPartialEq for ValidationError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> AnyExt for T
where T: Any + ?Sized,

§

fn downcast_ref<T>(this: &Self) -> Option<&T>
where T: Any,

Attempts to downcast this to T behind reference
§

fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>
where T: Any,

Attempts to downcast this to T behind mutable reference
§

fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>
where T: Any,

Attempts to downcast this to T behind Rc pointer
§

fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>
where T: Any,

Attempts to downcast this to T behind Arc pointer
§

fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>
where T: Any,

Attempts to downcast this to T behind Box pointer
§

fn downcast_move<T>(this: Self) -> Option<T>
where T: Any, Self: Sized,

Attempts to downcast owned Self to T, useful only in generic context as a workaround for specialization
§

impl<T> AsDebug for T
where T: Debug,

§

fn as_debug(&self) -> &dyn Debug

Returns self as a &dyn Debug trait object.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T, X> CoerceTo<T> for X
where T: CoerceFrom<X> + ?Sized,

§

fn coerce_rc_to(self: Rc<X>) -> Rc<T>

§

fn coerce_box_to(self: Box<X>) -> Box<T>

§

fn coerce_ref_to(&self) -> &T

§

fn coerce_mut_to(&mut self) -> &mut T

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<T> ServiceExt for T

§

fn map_response_body<F>(self, f: F) -> MapResponseBody<Self, F>
where Self: Sized,

Apply a transformation to the response body. Read more
§

fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using HTTP status codes. Read more
§

fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using gRPC headers. Read more
§

fn follow_redirects(self) -> FollowRedirect<Self>
where Self: Sized,

Follow redirect resposes using the Standard policy. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,