#[non_exhaustive]pub enum TreeError {
Show 15 variants
ManifestNotFound(PathBuf),
ManifestRead(String),
ManifestPermissionDenied {
path: PathBuf,
},
ManifestNotADir {
path: PathBuf,
},
ManifestIo {
path: PathBuf,
source: Error,
},
ManifestParse {
path: PathBuf,
detail: String,
},
Git(GitError),
CycleDetected {
chain: Vec<String>,
},
PackNameMismatch {
got: String,
expected: String,
path: PathBuf,
},
ChildPathInvalid {
child_name: String,
path: String,
reason: String,
},
LegacyLockfileDetected {
path: PathBuf,
},
UntrackedGitRepos {
paths: Vec<PathBuf>,
},
DirtyTreeRefusal {
path: PathBuf,
kind: DirtyTreeRefusalKind,
},
ManifestPathEscape {
path: String,
reason: String,
},
InvalidDestination {
path: PathBuf,
reason: String,
},
}Expand description
Errors raised during a pack-tree walk.
Marked #[non_exhaustive] so later slices (credentials, submodules,
partial walks) can add variants without breaking consumers.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
ManifestNotFound(PathBuf)
The walker expected a pack.yaml at the given location but could not
find one (or its enclosing .grex/ directory was missing).
ManifestRead(String)
The manifest file existed but could not be read from disk.
Catch-all fallback for io::ErrorKind cases that do not match a
categorised variant. Prefer TreeError::ManifestPermissionDenied,
TreeError::ManifestNotADir, or TreeError::ManifestIo when
the producer can route via io::Error::kind() /
is_not_a_directory. Retained for back-compat: v1.2.0+
downstream consumers may have matched this variant explicitly.
ManifestPermissionDenied
Manifest existed but the OS denied read access (POSIX EACCES /
Windows ERROR_ACCESS_DENIED). Operator-actionable: chmod /
icacls to grant the running user read on the file.
ManifestNotADir
Manifest path resolved to a non-directory entry where a directory
was expected (or the parent of the manifest path is not a
directory). Distinct from TreeError::ManifestNotFound — the
path exists but has the wrong type. Surfaces as ENOTDIR /
ERROR_DIRECTORY on the producer side; detection routed through
is_not_a_directory for MSRV 1.79 compatibility.
ManifestIo
Generic IO failure reading a manifest, preserving the underlying
io::Error for log routing without forcing the caller to
re-open the file. The catch-all path before the loader falls
through to TreeError::ManifestRead for kinds that don’t match
a categorised variant.
Fields
source: ErrorUnderlying OS error preserved for the std::error::Error
source chain.
ManifestParse
The manifest file was read but did not parse as a valid pack.yaml.
Fields
Git(GitError)
A git operation (clone, fetch, checkout, …) failed while hydrating a
child pack. The underlying GitError is preserved in full.
CycleDetected
A cycle was detected during the walk. chain lists the pack URLs (or
paths for the root) from the outermost pack down to the recurrence.
PackNameMismatch
A cloned child’s pack.yaml declared a name that does not match
what the parent pack expected for that children: entry.
Fields
ChildPathInvalid
A children[].path (or URL-derived tail) violated the bare-name
rule. Surfaced by the walker BEFORE any clone of the offending
child fires so a malicious path: ../escape in a parent pack
cannot materialise a directory outside the pack root. This is a
security boundary, not a soft validation concern — see
crates/grex-core/src/pack/validate/child_path.rs for the shared
rejection logic.
Fields
LegacyLockfileDetected
A v1.1.1-shape lockfile was encountered without the
--migrate-lockfile opt-in. v1.2.0 changed the on-disk lockfile
schema; the operator must explicitly run the migrator to convert
pre-existing lockfiles. Emitted by Stage 1.h walker entry-point
before any pack-tree work begins. Dormant until 1.h wires the
detector.
UntrackedGitRepos
One or more declared children own a .git/ directory but lack a
.grex/pack.yaml, and the v1.2.0 nested-children semantics
preclude the v1.1.1 “synthesize plain-git pack” fallback (e.g.
because a sibling explicitly opted out, or the parent manifest
disabled synthesis). Aggregated by Stage 1.e Phase 1; the walker
reports every offender in one go so the operator can fix the
manifest with a single pass.
DirtyTreeRefusal
Stage 1.f Phase 2 prune refused to remove a destination because
the recursive consent walk returned a non-Clean verdict.
kind discriminates the specific safety violation so the CLI
can suggest the correct override flag.
Fields
kind: DirtyTreeRefusalKindSpecific consent violation that triggered the refusal.
ManifestPathEscape
Stage 1.c validator rejected a child manifest segment that
resolved outside the parent pack root. Distinct from
TreeError::ChildPathInvalid — that variant rejects the
literal path: syntax (slashes, dots, absolute paths);
ManifestPathEscape is the post-resolution boundary check that
catches symlink-driven and platform-specific escapes.
Fields
InvalidDestination
v1.3.1 (B4) — a child’s resolved on-disk destination has no
usable UTF-8 file_name component. Surfaces during dry-run
record construction when dest.file_name() returns None (e.g.
the path ends in .. or is a filesystem root) or the component
is not UTF-8. Recording the child with an empty id would
silently corrupt the dry-run plan, so the walker pushes this
error into SyncMetaReport.errors instead and continues.
Trait Implementations§
Source§impl Error for TreeError
impl Error for TreeError
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()
Auto Trait Implementations§
impl Freeze for TreeError
impl !RefUnwindSafe for TreeError
impl Send for TreeError
impl Sync for TreeError
impl Unpin for TreeError
impl UnsafeUnpin for TreeError
impl !UnwindSafe for TreeError
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> 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> 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