Skip to main content

RunError

Enum RunError 

Source
#[non_exhaustive]
pub enum RunError {
Show 32 variants EmptyPrompt, BudgetExhausted { limit: u64, spent: u64, }, NoSuchSession, LegacyStore { dir: PathBuf, }, SessionRulesNotCleared { agent_id: String, error: RuntimeError, }, WorkspaceMismatch { agent_id: String, workspace: PathBuf, agent_workspace: PathBuf, }, Config(ConfigError), Context(ContextError), ResolvedModelProviderMismatch { model: String, model_provider: String, runtime_provider: String, }, RunProfileHeadersRequireEphemeralHistory, UnsupportedResumeProfile { field: &'static str, }, NonAtomicResumeProfile, DiscoveryDisabledSharedRuntime, FreshOnlySharedRuntime, FreshOnlyRunAlreadyAttempted, Provider(ProviderError), Runtime(RuntimeError), OutputMismatch(Error), Sink(Error), Forwarder(JoinError), Skills(SkillLoadError), Mcp(McpError), Templates(TemplateError), Memory(MemoryError), MemoryDiscovery(JoinError), Hooks(HookConfigError), WorkspaceGuardConflict { root: PathBuf, }, Tools(DeclaredToolError), CommandTarget { name: String, reason: String, }, WorkspaceHostToolName { name: String, reason: String, }, WorkspaceHostToolNameTaken { name: String, reason: String, }, HostTool(ToolNameCollision),
}
Expand description

Anything that can go wrong opening a workspace, preparing a run, or driving one.

One error type across all three, rather than a WorkspaceError beside it: opening a workspace exists to prepare runs, and every failure listed here is a failure a caller of run has always been able to receive.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

EmptyPrompt

§

BudgetExhausted

The shared allowance this turn draws on has nothing left.

A decision rather than a failure of the work, which is why it is its own variant: a caller fanning out over a BudgetPool stops minting on this, where it would retry on a provider error. Raised before the prompt is sent and before the stream opens, so the conversation is left exactly as it was.

Fields

§limit: u64
§spent: u64
§

NoSuchSession

§

LegacyStore

The directory named for this runtime’s conversations holds a basis ≤0.6 store — mentra’s SQLite database — which this build neither links nor migrates (ADR-0023).

basis’s own words rather than mentra’s: the upstream file store detects the same file and names its store-sqlite cargo feature, which is advice for a mentra embedder, not for the person whose conversations are in the file. Raised before any file store is opened in the directory, because an empty store beside the database would read as every conversation being lost. See store’s module docs for where the check runs.

Fields

§dir: PathBuf

The store directory holding the pre-0.7 database.

§

SessionRulesNotCleared

Resuming a conversation could not clear a pre-0.12 “…for this session” approval rule the conversation’s rules.json still carries, so the resume is refused rather than run with a grant or refusal a person gave to an earlier, unrelated session.

mentra 0.27’s process-scoped rung (mentra#53) means a new “…for this session” answer never touches the store — but a row an older basis binary remembered into the durable Session scope before this floor still sits in rules.json, and mentra still loads and matches Session-scope rows exactly as it always has. The clear reads rules.json before it can filter, so one corrupt, truncated, or unwritable file fails every resume against that store until the file is repaired or deleted. Fresh conversations, and any store no pre-0.12 binary ever wrote to, are unaffected.

Fields

§agent_id: String

The conversation whose resume was refused.

§error: RuntimeError

The store’s own failure, naming the file it could not read or rewrite.

§

WorkspaceMismatch

Workspace::resume was handed a conversation that belongs to a different workspace.

mentra’s store is keyed by agent, not by path, so an id alone says nothing about where its conversation ran — and everything a resume restates is this workspace’s: the policy carrying its .git carve-out and shell posture, the tool audience deciding which of the registry’s tools it can see, the persisted-row tag. Stamping those onto another repository’s conversation would run it under a posture nobody chose for it while its agent stayed based in its own directory — which mentra’s file tools always allow writes under. So the binding is checked against the persisted agent’s own base directory, and a mismatch is refused before the session is handed out.

A host that means “resume one of mine” takes the id from store::list for its own workspace, which is where a client got it anyway.

Fields

§agent_id: String

The conversation whose resume was refused.

§workspace: PathBuf

The workspace that tried to resume it.

§agent_workspace: PathBuf

The directory the persisted agent is actually based in.

§

Config(ConfigError)

§

Context(ContextError)

§

ResolvedModelProviderMismatch

Host-resolved model metadata names a provider other than the runtime’s.

Raised while opening a workspace, applying a per-run profile, or switching an attached PreparedRun, before model catalogue, model request, or tool activity. The mismatch cannot be repaired by looking up the id: provider identity is part of the host’s resolved contract.

Fields

§model: String

The host-resolved model id.

§model_provider: String

The provider named by the model metadata.

§runtime_provider: String

The provider registered on the runtime.

§

RunProfileHeadersRequireEphemeralHistory

Complete provider request options contain one or more extra headers, but this runtime can persist its Mentra agent configs.

Header names and values are deliberately absent: either can itself be sensitive. Use an explicitly ephemeral runtime for request-scoped credentials, or configure durable connection credentials on the provider instead.

§

UnsupportedResumeProfile

A RunProfile field Mentra cannot change on an already persisted agent.

Refused before the session is looked up or resumed, rather than projecting the supported subset and silently dropping part of the host’s contract. Resolved model metadata and the dedicated reasoning override are each supported alone through Mentra’s exact session setters; every other field is named here when present.

Fields

§field: &'static str

The first unsupported field in deterministic profile order.

§

NonAtomicResumeProfile

A resumed profile model would require separately persisting both model and reasoning changes, because the profile or an effective legacy effort also changes reasoning.

Mentra 0.23 exposes one setter for each but no atomic combined update. Refused before session lookup so a failed second write can never leave half of the host’s profile in force.

§

DiscoveryDisabledSharedRuntime

Discovery was disabled on a builder borrowing a shared runtime.

Mentra’s runtime-global skill loader can be changed after an Arc is borrowed, and its model-visible descriptions are read on every round. No one-time inspection can therefore prove that a shared runtime stays discovery-free. Gate 1a’s fresh-only lifecycle fails closed before runtime acquisition, model resolution, provider requests, workspace tool registration, or interception; use WorkspaceBuilder::with_runtime_builder so opening privately constructs the runtime it owns.

§

FreshOnlySharedRuntime

Fresh-only ownership was requested with a borrowed runtime.

§

FreshOnlyRunAlreadyAttempted

The workspace’s one independent mint/resume attempt was already used.

§

Provider(ProviderError)

§

Runtime(RuntimeError)

§

OutputMismatch(Error)

A typed turn answered, but not in the shape that was asked for.

Separate from Runtime because the two call for different reactions and basis can tell them apart honestly: this one is basis’s own verdict. The typed path asks mentra for the raw payload and deserializes it here, so a value that does not fit T is a schema or prompt problem — retry with a clearer schema — while a provider failure is not. The exchange stays in the session’s transcript either way; see PreparedRun::output, which delivers this inside an OutputFailure so the report the turn earned comes with it.

§

Sink(Error)

§

Forwarder(JoinError)

§

Skills(SkillLoadError)

§

Mcp(McpError)

§

Templates(TemplateError)

§

Memory(MemoryError)

§

MemoryDiscovery(JoinError)

The blocking thread WorkspaceBuilder::open runs memory discovery on (roots, per-file reads, canonicalize) panicked or was cancelled before it returned (whole-wave review, G7).

Not #[from]: Forwarder already claims tokio::task::JoinError for the event-forwarding task, and thiserror cannot generate two From impls for one source type on one enum — so this is built by hand at the one call site that needs it.

§

Hooks(HookConfigError)

§

WorkspaceGuardConflict

Two live opens of one workspace present different interception chains.

One directory is one tool audience, and a workspace registers its chain for that audience — so a second live open of the same root either joins the registration already there, which needs the two chains to be the same, or would put a second complete chain behind one audience. The second is not a middle ground: mentra would walk both for either open’s calls, spawning every subprocess hook twice per call and feeding a non-idempotent rewrite its own output, and the first open’s sessions would be judged by a chain their caller never configured. So identical chains join and different ones are refused here.

A host that genuinely needs two hook configurations for one directory needs two Runtimes. A host whose two opens differ only in their supplied MCP servers — basis-host’s deliberate shape — never meets this: the hooks come from one discovery configuration and are equal.

Fields

§root: PathBuf
§

Tools(DeclaredToolError)

§

CommandTarget

A command target name that cannot be routed on (ADR-0021).

Dormant: with with_command_target withdrawn, nothing can put a name in front of the validation that raises this, so build currently has no target to refuse. The variant keeps its slot in this #[non_exhaustive] enum for the day a registration seam returns.

Fields

§name: String
§reason: String
§

WorkspaceHostToolName

A host tool a workspace was given (WorkspaceBuilder::with_tool) under a name no tool may wear: empty, longer than a provider accepts, outside the charset, or mcp__-prefixed, which is how mentra names a bridged server’s tool.

The rules are the declared binding’s, called rather than restated — what may be a tool name does not depend on which binding put it there (crate::tools::host).

Fields

§name: String
§reason: String
§

WorkspaceHostToolNameTaken

The same tool, under a name that is well formed but not available.

Apart from WorkspaceHostToolName because the two carry different vocabularies and one sentence cannot host both: a malformed name is something (“has an empty name”), and an unavailable one is refused because of something else that is true. The declared binding splits its own refusals the same way (DeclaredToolError::Invalid beside NameTaken).

Four things can make a name unavailable: something this runtime already answers to globally (spawn, a mentra builtin, a RuntimeBuilder::with_tool global); another repository open on the same runtime; another live open of this directory; or the tool itself, if its descriptor named one thing when the name was claimed and another when it was registered.

The third is the one a host meets by accident. One directory is one tool audience, so two live opens of it share a namespace, and a native tool is compiled code closing over whatever the host had when it supplied it — there is no way to tell two of them apart, and joining would serve the second open the first one’s closure. A host that genuinely needs its own native tools per open of one directory needs one Runtime per open; a declaration, which is data, joins instead.

A sibling open that supplies nothing meets no error at all, and must not: it is refused nothing because it asked for nothing. What keeps it out of the tool it never supplied is not this variant but the pair that covers every shared-audience binding — hidden from its roster at the mint, and refused at the call by the guard in its own chain.

Either variant refuses the open rather than registering part of a set.

Fields

§name: String
§reason: String
§

HostTool(ToolNameCollision)

A host tool (RuntimeBuilder::with_tool) whose name collides with one basis already registered — spawn, a mentra builtin, or an earlier host tool on the same builder (decision D5d).

mentra’s registry is a map and its plain with_tool replaces, so without this a host tool named spawn would silently take over the name and inherit every rule an operator ever wrote about commands and delegation. Raised by build, after basis’s own registrations exist to collide against, rather than a silent swap.

Implementations§

Source§

impl RunError

Source

pub fn is_open_elsewhere(&self) -> bool

Whether this failure means another holder already has the conversation open.

Trait Implementations§

Source§

impl Debug for RunError

Source§

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

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

impl Display for RunError

Source§

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

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

impl Error for RunError

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 From<ConfigError> for RunError

Source§

fn from(source: ConfigError) -> Self

Converts to this type from the input type.
Source§

impl From<ContextError> for RunError

Source§

fn from(source: ContextError) -> Self

Converts to this type from the input type.
Source§

impl From<DeclaredToolError> for RunError

Source§

fn from(source: DeclaredToolError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for RunError

Source§

fn from(source: Error) -> Self

Converts to this type from the input type.
Source§

impl From<HookConfigError> for RunError

Source§

fn from(source: HookConfigError) -> Self

Converts to this type from the input type.
Source§

impl From<JoinError> for RunError

Source§

fn from(source: JoinError) -> Self

Converts to this type from the input type.
Source§

impl From<McpError> for RunError

Source§

fn from(source: McpError) -> Self

Converts to this type from the input type.
Source§

impl From<MemoryError> for RunError

Source§

fn from(source: MemoryError) -> Self

Converts to this type from the input type.
Source§

impl<S> From<OutputFailure<S>> for RunError

Source§

fn from(failure: OutputFailure<S>) -> Self

The error alone, worded exactly as the typed turn worded it before it carried a report. The report — and with it the sink — is dropped here, which is the whole cost of ? and the reason the richer type is what the turn returns.

Source§

impl From<ProviderError> for RunError

Source§

fn from(source: ProviderError) -> Self

Converts to this type from the input type.
Source§

impl<S> From<RunError> for OutputFailure<S>

Source§

fn from(error: RunError) -> Self

A failure with no turn behind it. See report.

Source§

impl From<RuntimeError> for RunError

Source§

fn from(source: RuntimeError) -> Self

Converts to this type from the input type.
Source§

impl From<SkillLoadError> for RunError

Source§

fn from(source: SkillLoadError) -> Self

Converts to this type from the input type.
Source§

impl From<TemplateError> for RunError

Source§

fn from(source: TemplateError) -> Self

Converts to this type from the input type.
Source§

impl From<ToolNameCollision> for RunError

Source§

fn from(source: ToolNameCollision) -> Self

Converts to this type from the input type.

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
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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

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

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

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

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

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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + 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
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + 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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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 = !

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

fn try_from(value: U) -> Result<T, !>

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.
Source§

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

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

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

fn with_current_subscriber(self) -> WithDispatch<Self>

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