Skip to main content

CoreError

Enum CoreError 

Source
pub enum CoreError {
Show 36 variants Internal(String), ConfirmationRequired { operation: String, }, InvalidImportFile { reason: String, }, ImportDenied { project: String, problem: String, endpoint: Option<String>, }, InvalidInput { reason: String, }, ProfileNotFound { name: String, known: Vec<String>, }, NoActiveProfile, SecretUnavailable { profile: String, }, ConfigInvalid { reason: String, }, PollIntervalTooSmall { profile: String, }, Network { url: String, source: Option<Error>, observation: Option<String>, }, Auth { status: u16, endpoint: Option<String>, }, GatewayTooOld { found: String, minimum: String, endpoint: Option<String>, }, GatewayNotCommissioned { endpoint: Option<String>, }, GatewayRestarting { endpoint: Option<String>, }, NotFound { endpoint: Option<String>, }, ProjectExists { name: String, endpoint: Option<String>, }, ResourceBinary { path: String, endpoint: Option<String>, }, TrialNotExpired { remaining_s: i64, endpoint: Option<String>, }, RoutesNotDeployed { project: String, route: String, endpoint: Option<String>, }, WebdevUnlicensed { endpoint: Option<String>, }, RouteVersionMismatch { route: String, deployed: String, expected: String, endpoint: Option<String>, }, ProviderNotFound { name: String, endpoint: Option<String>, }, WebdevRouteError { code: String, message: String, endpoint: Option<String>, }, TagCollision { provider: String, names: Vec<String>, endpoint: Option<String>, }, AlarmJournalMissing { endpoint: Option<String>, }, SessionNotPrunable { id: String, endpoint: Option<String>, }, Rig(String), EamNotController { endpoint: Option<String>, }, ProviderRootUnsupported { endpoint: Option<String>, }, EamTaskTypeRefused { task_type: String, }, EamTaskInFlight { task: String, detail: String, endpoint: Option<String>, }, ScriptExecNotConfigured { profile: String, }, LintToolAbsent, GatewayClientError { status: u16, endpoint: String, body: String, }, BundleNotAvailable { state: String, },
}
Expand description

Every failure ign can report. One variant per contract class; code(), exit_code(), hint() are total functions over it.

Variants§

§

Internal(String)

Unexpected runtime failure — the catch-all; report as a bug. Exit 1.

§

ConfirmationRequired

Destructive operation invoked without --yes. Exit 2 (same class as usage: it names a flag the caller must add; clap renders its own usage errors with its exit 2 — never hook clap).

Fields

§operation: String
§

InvalidImportFile

An import byte source the caller must fix (wrong file, too big, unreadable). Exit 2 — usage class: it names what the CALLER must change, like Self::ConfirmationRequired (03-02).

Fields

§reason: String
§

ImportDenied

The gateway ANSWERED the import POST with HTTP 200 but the body says {"success": false, "problem": "…"} — the denial-rides-200 class the WebDev family handles (05-01) applied to the project-import family (05-07, UAT Gap 1): without this check the import caller reports ok while nothing landed. Exit 6 — target state: the gateway refused the import (the problem text names why, verbatim).

Fields

§project: String

The project the import was headed for.

§problem: String

The gateway’s own problem text (verbatim when present).

§endpoint: Option<String>

URL of the import request, when known.

§

InvalidInput

A command input the caller must fix (unreadable --file, failed stdin read). Exit 2 — usage class, the generic sibling of Self::InvalidImportFile (03-03: resource put’s byte source).

Fields

§reason: String
§

ProfileNotFound

Named profile absent from config. Exit 3.

Fields

§name: String
§known: Vec<String>
§

NoActiveProfile

No --profile, no IGNITION_PROFILE, no active profile in config. Exit 3. Constructible from the CLI once config resolution lands (01-03); the taxonomy is complete on day one.

§

SecretUnavailable

No credential resolvable for the profile (env, token_env, keyring all missed or failed). Exit 3.

Fields

§profile: String
§

ConfigInvalid

Config file unreadable or wrong shape. Exit 3.

Fields

§reason: String
§

PollIntervalTooSmall

A profile’s poll_interval_secs is below the 1-second floor (08-01, TUIX-05 clamp): sub-second gateway polling is refused at load time — the TUI’s background refresh cadence may not hammer the gateway. Exit 3 — the CONFIG class (the Phase-7 additive-slug precedent, e.g. eam_not_controller: same exit class, own slug, never a new exit code — the 1–7 taxonomy is frozen).

Fields

§profile: String

The profile carrying the refused value.

§

Network

Gateway unreachable / timeout / TLS failure. Exit 4.

source: None marks a POLL deadline expiry (02-04 poll.rs): same class, same slug (network_error), no new variant — the transport-error source a real failure carries is simply absent, and url describes what was being waited on instead (the poll’s subject). The deadline’s last observation rides observation (09-07): when it is Some the gateway ANSWERED with a concrete state, and the message leads with “no terminal state” — it NEVER claims unreachability for an observed answer; None keeps the plain unreachability wording.

Fields

§source: Option<Error>
§observation: Option<String>

The poll deadline’s last concrete observation (e.g. the gateway’s reported state) — None for transport failures and observation-less deadlines. Some ⇒ the gateway answered; the Display never says “unreachable” then.

§

Auth

Gateway reachable but rejected credentials (401/403). Exit 5.

Fields

§status: u16
§endpoint: Option<String>

URL/path of the request that was rejected, when known.

§

GatewayTooOld

Gateway reachable but the command is invalid for its current state — version below minimum, uncommissioned, mid-restart, or a missing resource. Exit 6.

Fields

§found: String
§minimum: String
§endpoint: Option<String>

URL/path of the request that answered, when known.

§

GatewayNotCommissioned

Gateway reachable but uncommissioned — every /data route 302s to /welcome (verified on a fresh 8.3.6 container; 02-RESEARCH §Error-Body Sniffing). Exit 6.

Fields

§endpoint: Option<String>

URL that was redirected to the commissioning wizard.

§

GatewayRestarting

Gateway restarting — webserver answers (503) but services are down (verified restart lifecycle: webserver never drops the connection). Exit 6.

Fields

§endpoint: Option<String>

URL that answered 503.

§

NotFound

Named resource absent (404) — terminating a nonexistent session id, an unknown path, or a pre-8.3 gateway’s JSON {"message": "No route match for path: …"}. Exit 6.

Fields

§endpoint: Option<String>

URL that answered 404.

§

ProjectExists

A project of this name already exists and the import’s collision policy is abort — the CLI-side pre-check refused BEFORE any upload (the server’s own answer remains the backstop). Exit 6 — target state: the command is invalid for the gateway’s current state (03-02, the GatewayTooOld action-built-variant precedent: constructed by the actions layer, not classify).

Fields

§name: String

The colliding project name.

§endpoint: Option<String>

URL of the pre-check request, when known.

§

ResourceBinary

A binary (data.bin-class) resource met the surgical JSON/text loop — REFUSED rather than corrupted through it. Exit 6 — target state: the command is invalid for that resource’s nature; the export/import family owns binary resources (Pitfall 7).

Fields

§path: String

The resource path that was refused.

§endpoint: Option<String>

URL of the request involved, when known.

§

TrialNotExpired

The gateway refuses trial resets while the trial is still active — live-discovered on 8.3.3 during 04-03’s spike: the reset POST answers 403 on a NON-expired trial (verified from the browser page itself with the exact UI headers), and 200 + the flip on an expired one. The action layer’s expiry pre-check turns that misleading auth-shaped 403 into the honest target-state refusal. Exit 6 (the ProjectExists precedent: action-constructed, not classify).

Fields

§remaining_s: i64

Seconds left on the active trial.

§endpoint: Option<String>

URL of the rig’s trial endpoint, when known.

§

RoutesNotDeployed

The WebDev route family a command depends on is not deployed — the presence probe answered 405, the live-proven 8.3 absent marker (missing routes AND missing projects both answer 405, NOT 404; 05-RESEARCH Pitfall 1). Exit 6 — target state: the command is invalid until ign webdev deploy installs the routes (the TrialNotExpired precedent: action-constructed, not classify).

Fields

§project: String

The deploy project the probe targeted.

§route: String

The route folder the probe named.

§endpoint: Option<String>

Path of the probe request, when known.

§

WebdevUnlicensed

The WebDev module answered 402 — installed but unlicensed (a trial-expired gateway; live-verified cross-version on 8.3.6, 05-RESEARCH §Servlet). Exit 6 — no /system/webdev route can answer until the gateway is licensed.

Fields

§endpoint: Option<String>

Path of the probe request, when known.

§

RouteVersionMismatch

A deployed route’s handshake version differs from the embedded bundle’s — the CLI refuses rather than auto-upgrading either side (roadmap-locked: actionable error, no auto-upgrade magic). Exit 6.

Fields

§route: String

The route folder that answered.

§deployed: String

The route’s deployed routeVersion.

§expected: String

The embedded bundle’s version (crate::webdev::ROUTE_BUNDLE_VERSION).

§endpoint: Option<String>

Path of the probe request, when known.

§

ProviderNotFound

A tag provider of this name does not exist — the find→signature→delete chain’s find half missed (05-04, TAGS-01). Exit 6 — target state: the named thing is absent (the ProjectExists precedent family: action-constructed, not classify — the honest, family-specific refusal over a bare 404).

Fields

§name: String

The provider name that missed.

§endpoint: Option<String>

URL of the find request, when known.

§

WebdevRouteError

A WebDev route answered HTTP 200 with a body denial ({ok:false, error{code,message}}) whose machine code this CLI does not specifically map — code + message ride verbatim so agents can branch on the stable route contract (05-01). Exit 6 — target state: the deployed route refused the action.

Fields

§code: String

The route’s machine error code (stable contract).

§message: String

The route’s human message.

§endpoint: Option<String>

Path of the request, when known.

§

TagCollision

A tag import under abort policy found EXISTING tags at the target provider (05-05, TAGS-09) — the browse pre-check refuses BEFORE any route write (the LOCKED Phase-3 collision matrix mapped onto configure’s ‘a’/‘o’). Exit 6 — target state: the named tags exist; overwrite is the explicit, guarded opt-in.

Fields

§provider: String

The target provider the import was headed for.

§names: Vec<String>

The colliding top-level tag names the pre-check found.

§endpoint: Option<String>

URL of the pre-check browse request, when known.

§

AlarmJournalMissing

The gateway has no alarm-journal profile configured — alarm history has nowhere to read from. The alarms route’s structured no_alarm_journal denial maps here (the denial_to_error seam, 05-06 TAGS-07): DEFAULT rigs hit this ALWAYS, because the journal is a config-resource chain — database connection + ignition/alarm-journal profile + the general-alarm-settings singleton pointing at it. Exit 6 — target state: the command is invalid for the gateway’s current state until that chain is provisioned (the honest, actionable refusal over a bare route error).

Fields

§endpoint: Option<String>

URL of the alarms route request, when known.

§

SessionNotPrunable

Pruning a LIVE Designer session entry — the gateway’s prune route answers 409 (empty body, wire-verified on 8.3.3, 06-UAT test 6): prune removes STALE entries only, so the command is invalid while the Designer is still open. Exit 6 — target state (additive slug in the frozen taxonomy’s established growth pattern; classify()’s ROUTE-SCOPED 409 arm constructs this — the first classify-constructed refusal added since the 02-01 set).

Fields

§id: String

The Designer session id that was refused.

§endpoint: Option<String>

URL of the refused DELETE, when known.

§

Rig(String)

Docker/compose rig failure. Exit 7. Reserved — first used in Phase 4; trivially constructible so the taxonomy enumerates completely today.

§

EamNotController

The gateway’s EAM module is not configured as a controller — every /data/eam/api/v1/* runtime endpoint answers 403 with “This operation can only be performed when EAM is configured as a controller” on a stock gateway (live-proven 8.3.3, 07-RESEARCH): a STATE refusal, not auth — the token is fine, the module’s role is not. Message-classified at the classify seam, path-scoped to /data/eam/ so generic 403s elsewhere cannot shift (the trial_not_expired pattern, classify edition). Exit 6 — target state.

Fields

§endpoint: Option<String>

URL of the refused request, when known.

§

ProviderRootUnsupported

A provider-ROOT tag path ([default] alone, or a bare first segment that resolves to a provider) met the tagConfig route — system.tag.getConfiguration/exportTags need an RPC context WebDev threads don’t carry (live-proven 8.3.3 b2026012009, both gateways; 07-UAT test 12). The route refuses honestly (pre-call bracket detection + RpcContext translation for the bare form) instead of surfacing the IllegalStateException as a generic route error; subtree paths ([default]folder) are the supported form. Exit 6 — target state: a platform limitation, not a bug.

Fields

§endpoint: Option<String>

URL of the tagConfig route request, when known.

§

EamTaskTypeRefused

An eam task new whose type is in the REFUSED set — eam_restoreBackup, eam_installModules, eam_remoteUpgrade are fleet-destructive (they push backups/modules/upgrades to every AGENT target), and the CLI refuses them outright over guard-everything: honest refusal with the v2 scope pointer (the planner-locked create ladder’s top rung). Exit 6 — target state (additive slug alongside Task 2’s).

Fields

§task_type: String

The refused profile.type token.

§

EamTaskInFlight

An eam task force whose slot a leftover run occupies — the force route answers 409 with the gateway’s own Jetty page (“Task ‘X (forced)’ already exists! It must be completed or deleted before another task of this type can be force executed.”; live-captured 8.3.3, 07-UAT test 7). Exit 6 — target state (the session_not_prunable precedent, force-route edition): the gateway’s state refused the command, not a bug; classify()’s path-scoped 409 arm constructs this.

Fields

§task: String

The forced task’s name (the force URL’s last segment).

§detail: String

The gateway’s Jetty page message verbatim when sniffed; the ‘(forced)’ fallback text otherwise.

§endpoint: Option<String>

URL of the refused force POST, when known.

§

ScriptExecNotConfigured

The scriptExec route is not configured for this profile — no webdev secret is persisted, which can only mean ign webdev deploy --with-script-exec has never run (deploy persists the secret 0600 BEFORE upload, so a deployed route without a stored secret is not a reachable state). ign script run’s opt-in is STRUCTURAL — the deploy flag — so the verb carries no --yes guard and refuses here instead (07-03, SCRPT-01: the TrialNotExpired precedent — action-constructed, not classify). Exit 6 — target state.

Fields

§profile: String

The profile whose secret store is empty.

§

LintToolAbsent

ign lint found no ignition-lint executable on PATH — the delegation has nothing to delegate to (07-04, INTR-02). The hint carries the install command + repo. Exit 6 — target state (additive slug; the environment lacks the tool, the command is fine).

§

GatewayClientError

The gateway answered the api call with a 4xx this CLI does not curate — the caller’s request is the problem, and the body is theirs to read. Exit 2 (usage class; additive slug — the poll_interval_too_small precedent: same class, own slug, no new exit code). Constructed ONLY by the api-call-scoped classify arm (09-01: the api_call parameter) — a curated command’s 4xx keeps its existing classification (the catch-all cannot fire without the parameter). The body is the gateway’s answer VERBATIM, truncated at GATEWAY_CLIENT_BODY_CAP_BYTES with the explicit GATEWAY_CLIENT_BODY_TRUNCATION_MARKER via truncate_api_body at construction.

Fields

§status: u16

HTTP status the gateway answered with.

§endpoint: String

Full URL of the rejected request.

§body: String

The response body VERBATIM, truncated at GATEWAY_CLIENT_BODY_CAP_BYTES with an explicit marker.

§

BundleNotAvailable

No diagnostics bundle is available — the status poll ANSWERED with a captured TERMINAL steady state meaning “no current bundle” (Invalid: live-proven on 8.3.6 rig ign-p9-836, 2026-09-07 UAT / 09-UAT.md Gap 3 — a Valid bundle decays to Invalid within ~2 minutes UNPROMPTED and stays Invalid; only a fresh generate changes it, polling cannot). Exit 6 — target state (the ImportDenied precedent: a gateway-answered refusal riding its own class, action-constructed by bundle wait’s probe, not classify).

Fields

§state: String

The observed steady state (the captured unavailable vocabulary, e.g. Invalid).

Implementations§

Source§

impl CoreError

Source

pub fn code(&self) -> &'static str

Stable machine slug — public contract, never respell.

Source

pub fn exit_code(&self) -> u8

The LOCKED exit-code mapping — the only place exit codes are decided.

Source

pub fn hint(&self) -> Option<String>

Actionable next step (CORE-05). Every class carries one.

Source

pub fn endpoint(&self) -> Option<String>

URL/path of the request involved, when one was — populated for the network, auth, and target-state classes (CORE-05).

Source

pub fn tui_tty_refusal() -> Self

The ign tui TTY refusal (06-07): InvalidInput carrying the ONE reason whose hint is terminal-contextual — see TUI_TTY_REFUSAL_REASON. Same slug, same exit 2 (frozen taxonomy; only the hint differs).

Source

pub fn envelope<'a>(&self, profile: Option<&'a str>) -> ErrorEnvelope<'a>

Build the LOCKED failure envelope for this error (field order is part of the golden contract: ok, profile, error then code, message, endpoint, hint).

Trait Implementations§

Source§

impl Debug for CoreError

Source§

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

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

impl Display for CoreError

Source§

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

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

impl Error for CoreError

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

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

Source§

type Output = T

Should always be Self
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<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