pub enum Error {
Show 16 variants
NotFound,
PermissionDenied,
NoFilesystem,
Unavailable,
Foreign,
Damaged,
Failed,
Unreachable,
Busy,
OutcomeUnknown,
PeerDied,
Malformed,
Cancelled,
Revoked,
BufferTooSmall,
InvalidInput,
}Expand description
Everything a Godspeed operation can fail with.
Deliberately small. Each variant exists because a caller would do something DIFFERENT about it; a distinction nobody would act on belongs in a log line, not in a type.
Variants§
NotFound
No such file or directory. The service is healthy; the path is not there.
PermissionDenied
The operation needs a right this capability does not carry (§7.3 non-escalation). Asking again cannot help: rights never widen.
NoFilesystem
The volume is not mounted, or holds no GodspeedOS filesystem.
The storage is present but unreadable. Data may still be intact, so this is NOT an invitation to reformat.
Foreign
The disk holds a foreign partition table. Refused deliberately rather than overwritten.
Damaged
The file is there, and a block of it failed its checksum or could not be read: it is DAMAGED,
not missing. drives scrub names every such block. fs answered this as “not found” until
2026-10-10 (backlog/fixed/80 V2).
Failed
The service tried and failed, and said so. A real failure with a real answer behind it.
Unreachable
The request never left this task: the peer’s capability is stale because it restarted
(§14.2), or its name does not currently resolve. Nothing happened. Retrying after
reacquiring the peer by name reaches the fresh instance, which crate::call::request_within
already does for you once - for a send that never left, and for nothing else. A request that
was delivered is never re-sent (Error::OutcomeUnknown, Error::PeerDied).
Busy
The peer is alive and its queue is full. Nothing happened. Congestion is transient by definition: pace and retry, and do not go looking for a peer that never went anywhere.
OutcomeUnknown
The deadline passed with no reply. The operation may have completed. The peer may be
slow, or may be wedged. (A peer that DIED holding the request is Error::PeerDied on the
CallDeadline path, crate::call::request_within; only paths that wait with a plain timed
receive, such as crate::call::request_within_notice with a callback, report a death here
too, because no ReplyDead reaches them.) This is the one failure you must
not paper over: for anything that changes state, report it or re-read the truth, never
re-send.
PeerDied
The request ARRIVED and the service died before answering it (the kernel’s ReplyDead,
CLAUDE.md 8.6). The operation may have completed, exactly as with Error::OutcomeUnknown,
so this is not safe to re-send blindly either.
It is its own variant because the caller does two things differently. It does not wait out a deadline or call the peer “silent” - the peer is gone, and saying it was slow sends an operator after the wrong fault. And it REACQUIRES before anything else, because the instance it asked no longer exists. For an operation that is safe to repeat - a read, a block transfer of the same sector - reacquire and ask again; that was what callers did before this variant existed, and now they say so.
Malformed
A reply came back that this library could not parse: too short, wrong tag, or a status byte outside the protocol. A bug somewhere, not a condition to handle - but it is reported rather than guessed past, because guessing is how a wrong byte index becomes a wrong answer.
Cancelled
The caller stopped waiting - a person pressed q, or the program gave up on purpose.
Not a fault, and the distinction is load-bearing: services/shell says it plainly, that “the
user’s own q is NOT a fault - reporting it as one teaches the operator to distrust the error
line, which is the thing they most need to trust”. A cancelled operation should be reported as
cancelled, never as a failure.
It is still not safe to retry blindly. The request may already have been delivered and acted on; cancelling only means this caller stopped listening.
Revoked
The capability is no longer valid: whatever issued it revoked it, or died and was replaced (7.5 - a generation bump invalidates every outstanding cap).
The kernel refused this before the owning service was reached, so nothing happened and
nothing was asked of anyone. Distinct from Error::Unreachable on purpose: the service is
very likely up and well. Reporting this as “could not be reached” sends an operator to check
a service that is running perfectly.
retry_is_safe is false here, and for the less obvious of its
two reasons: a repeat cannot double-apply anything (the kernel refused before routing), but
it can never succeed either, and a caller looping on that predicate would spin forever.
Re-open the resource - and remember that a capability obtained from a service’s PREVIOUS instance is stale even after you reacquire that service by name (14.3).
BufferTooSmall
The caller’s buffer is too small for the answer. Nothing was consumed; call again with room.
InvalidInput
The request could not be built: a path longer than the protocol allows, or a payload past the message ceiling. It was never sent.
Implementations§
Source§impl Error
impl Error
Sourcepub fn retry_is_safe(self) -> bool
pub fn retry_is_safe(self) -> bool
May I simply send this again?
true only when the request provably never reached the service, so a retry is the same
operation rather than a second one. false for OutcomeUnknown even though a retry might
work, because “might” is not good enough when the first attempt may already have committed.
For a read-only operation the caller may retry regardless; this is about what the LIBRARY can promise without knowing what the request was.
Sourcepub fn service_answered(self) -> bool
pub fn service_answered(self) -> bool
true when the service answered. Distinguishes “no” from “no answer”, which is the coarse
version of the distinction above and often the only one a caller needs.