Skip to main content

errors/
lib.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use ::routing::error::{ComponentInstanceError, RoutingError};
6use ::routing::policy::PolicyError;
7use ::routing::resolving::ResolverError;
8use anyhow::Error;
9use clonable_error::ClonableError;
10use cm_config::CompatibilityCheckError;
11use cm_rust::UseDecl;
12use cm_types::{Name, Url};
13use component_id_index::InstanceId;
14use fidl_fuchsia_component as fcomponent;
15use fidl_fuchsia_sys2 as fsys;
16use fuchsia_fs::directory::WatcherCreateError;
17use moniker::{ChildName, ExtendedMoniker, Moniker, MonikerError};
18use router_error::{Explain, RouterError};
19use runtime_capabilities::ConversionError;
20use serve_processargs::BuildNamespaceError;
21use std::sync::Arc;
22use thiserror::Error;
23
24/// Errors produced by `Model`.
25#[derive(Debug, Error, Clone)]
26pub enum ModelError {
27    #[error("bad path")]
28    BadPath,
29    #[error(transparent)]
30    MonikerError {
31        #[from]
32        err: MonikerError,
33    },
34    #[error("expected a component instance moniker")]
35    UnexpectedComponentManagerMoniker,
36    #[error(transparent)]
37    RoutingError {
38        #[from]
39        err: RoutingError,
40    },
41    #[error(
42        "opening path `{path}`, in storage directory for `{moniker}` backed by `{source_moniker}`: {err}"
43    )]
44    OpenStorageFailed {
45        source_moniker: ExtendedMoniker,
46        moniker: Moniker,
47        path: String,
48        #[source]
49        err: zx::Status,
50    },
51    #[error(transparent)]
52    StorageError {
53        #[from]
54        err: StorageError,
55    },
56    #[error(transparent)]
57    ComponentInstanceError {
58        #[from]
59        err: ComponentInstanceError,
60    },
61    #[error("service dir VFS for component {moniker}:\n\t{err}")]
62    ServiceDirError {
63        moniker: Moniker,
64
65        #[source]
66        err: VfsError,
67    },
68    #[error("opening directory `{relative_path}` for component `{moniker}` failed")]
69    OpenDirectoryError { moniker: Moniker, relative_path: String },
70    #[error("events: {err}")]
71    EventsError {
72        #[from]
73        err: EventsError,
74    },
75    #[error(transparent)]
76    PolicyError {
77        #[from]
78        err: PolicyError,
79    },
80    #[error("component id index: {err}")]
81    ComponentIdIndexError {
82        #[from]
83        err: component_id_index::IndexError,
84    },
85    #[error(transparent)]
86    ActionError {
87        #[from]
88        err: ActionError,
89    },
90    #[error("resolve: {err}")]
91    ResolveActionError {
92        #[from]
93        err: ResolveActionError,
94    },
95    #[error("start: {err}")]
96    StartActionError {
97        #[from]
98        err: StartActionError,
99    },
100    #[error("open outgoing dir: {err}")]
101    OpenOutgoingDirError {
102        #[from]
103        err: OpenOutgoingDirError,
104    },
105    #[error("router: {err}")]
106    RouterError {
107        #[from]
108        err: RouterError,
109    },
110    #[error("capability provider: {err}")]
111    CapabilityProviderError {
112        #[from]
113        err: CapabilityProviderError,
114    },
115    #[error("open: {err}")]
116    OpenError {
117        #[from]
118        err: OpenError,
119    },
120}
121
122impl ModelError {
123    pub fn instance_not_found(moniker: Moniker) -> ModelError {
124        ModelError::from(ComponentInstanceError::instance_not_found(moniker))
125    }
126
127    pub fn open_directory_error(moniker: Moniker, relative_path: impl Into<String>) -> ModelError {
128        ModelError::OpenDirectoryError { moniker, relative_path: relative_path.into() }
129    }
130}
131
132impl ModelError {
133    fn as_zx_status(&self) -> zx::Status {
134        match self {
135            ModelError::RoutingError { err } => err.as_zx_status(),
136            ModelError::PolicyError { err } => err.as_zx_status(),
137            ModelError::StartActionError { err } => err.as_zx_status(),
138            ModelError::ComponentInstanceError { err } => err.as_zx_status(),
139            ModelError::OpenOutgoingDirError { err } => err.as_zx_status(),
140            ModelError::RouterError { err } => err.as_zx_status(),
141            ModelError::CapabilityProviderError { err } => err.as_zx_status(),
142            // Any other type of error is not expected.
143            _ => zx::Status::INTERNAL,
144        }
145    }
146}
147
148#[derive(Debug, Error, Clone)]
149pub enum StructuredConfigError {
150    #[error("component has a config schema but resolver did not provide values")]
151    ConfigValuesMissing,
152    #[error("failed to resolve component's config:\n\t{_0}")]
153    ConfigResolutionFailed(#[source] config_encoder::ResolutionError),
154    #[error("couldn't create vmo: {_0}")]
155    VmoCreateFailed(#[source] zx::Status),
156    #[error("failed to match values for key `{key}`")]
157    ValueMismatch { key: String },
158    #[error("failed to find values for key `{key}`")]
159    KeyNotFound { key: String },
160    #[error("failed to route structured config values:\n\t{_0}")]
161    RoutingError(#[from] router_error::RouterError),
162}
163
164#[derive(Clone, Debug, Error)]
165pub enum VfsError {
166    #[error("failed to add node `{name}`: {status}")]
167    AddNodeError { name: String, status: zx::Status },
168    #[error("failed to remove node `{name}`: {status}")]
169    RemoveNodeError { name: String, status: zx::Status },
170}
171
172#[derive(Debug, Error)]
173pub enum RebootError {
174    #[error("failed to connect to admin protocol in root component's exposed dir:\n\t{0}")]
175    ConnectToAdminFailed(#[source] anyhow::Error),
176    #[error("StateControl Admin FIDL:\n\t{0}")]
177    FidlError(#[from] fidl::Error),
178    #[error("StateControl Admin: {0}")]
179    AdminError(zx::Status),
180    #[error("opening root component's exposed dir: {0}")]
181    OpenRootExposedDirFailed(#[from] OpenExposedDirError),
182}
183
184#[derive(Debug, Error)]
185pub enum OpenExposedDirError {
186    #[error("instance is not resolved")]
187    InstanceNotResolved,
188    #[error("instance was destroyed")]
189    InstanceDestroyed,
190    #[error("open error: {0}")]
191    Open(#[from] zx::Status),
192}
193
194impl Explain for OpenExposedDirError {
195    fn as_zx_status(&self) -> zx::Status {
196        match self {
197            Self::InstanceNotResolved => zx::Status::NOT_FOUND,
198            Self::InstanceDestroyed => zx::Status::NOT_FOUND,
199            Self::Open(status) => *status,
200        }
201    }
202}
203
204impl From<OpenExposedDirError> for fsys::OpenError {
205    fn from(value: OpenExposedDirError) -> Self {
206        match value {
207            OpenExposedDirError::InstanceNotResolved => fsys::OpenError::InstanceNotResolved,
208            OpenExposedDirError::InstanceDestroyed => fsys::OpenError::InstanceDestroyed,
209            OpenExposedDirError::Open(_) => fsys::OpenError::FidlError,
210        }
211    }
212}
213
214#[derive(Clone, Debug, Error)]
215pub enum OpenOutgoingDirError {
216    #[error("instance is not resolved")]
217    InstanceNotResolved,
218    #[error("instance is non-executable")]
219    InstanceNonExecutable,
220    #[error("failed to open: {0}")]
221    Open(#[from] zx::Status),
222    #[error("fidl IPC to protocol in outgoing directory:\n\t{0}")]
223    Fidl(fidl::Error),
224}
225
226impl Explain for OpenOutgoingDirError {
227    fn as_zx_status(&self) -> zx::Status {
228        match self {
229            Self::InstanceNotResolved => zx::Status::NOT_FOUND,
230            Self::InstanceNonExecutable => zx::Status::NOT_FOUND,
231            Self::Open(err) => *err,
232            Self::Fidl(_) => zx::Status::NOT_FOUND,
233        }
234    }
235}
236
237impl From<OpenOutgoingDirError> for fsys::OpenError {
238    fn from(value: OpenOutgoingDirError) -> Self {
239        match value {
240            OpenOutgoingDirError::InstanceNotResolved => fsys::OpenError::InstanceNotResolved,
241            OpenOutgoingDirError::InstanceNonExecutable => fsys::OpenError::NoSuchDir,
242            OpenOutgoingDirError::Open(_) => fsys::OpenError::FidlError,
243            OpenOutgoingDirError::Fidl(_) => fsys::OpenError::FidlError,
244        }
245    }
246}
247
248impl From<OpenOutgoingDirError> for RouterError {
249    fn from(value: OpenOutgoingDirError) -> Self {
250        Self::NotFound(Arc::new(value))
251    }
252}
253
254#[derive(Debug, Error, Clone)]
255pub enum AddDynamicChildError {
256    #[error("component collection not found with name `{name}`")]
257    CollectionNotFound { name: String },
258    #[error(
259        "numbered handles can only be provided when adding components to a single-run collection"
260    )]
261    NumberedHandleNotInSingleRunCollection,
262    #[error("name length is longer than the allowed max of {max_len}")]
263    NameTooLong { max_len: usize },
264    #[error("collection `{collection_name}` does not allow dynamic offers")]
265    DynamicOffersNotAllowed { collection_name: String },
266    #[error(transparent)]
267    ActionError {
268        #[from]
269        err: ActionError,
270    },
271    #[error("invalid dictionary")]
272    InvalidDictionary,
273    #[error(
274        "dictionary entry for capability `{capability_name}` conflicts with existing static route"
275    )]
276    StaticRouteConflict { capability_name: Name },
277    #[error(transparent)]
278    AddChildError {
279        #[from]
280        err: AddChildError,
281    },
282    #[error("cannot set both `dictionary` and `additional_inputs`")]
283    DictionaryAndAdditionalInputsSet,
284}
285
286// This is implemented for fuchsia.component.Realm protocol
287impl Into<fcomponent::Error> for AddDynamicChildError {
288    fn into(self) -> fcomponent::Error {
289        match self {
290            AddDynamicChildError::CollectionNotFound { .. } => {
291                fcomponent::Error::CollectionNotFound
292            }
293            AddDynamicChildError::NumberedHandleNotInSingleRunCollection => {
294                fcomponent::Error::Unsupported
295            }
296            AddDynamicChildError::AddChildError {
297                err: AddChildError::InstanceAlreadyExists { .. },
298            } => fcomponent::Error::InstanceAlreadyExists,
299            AddDynamicChildError::DynamicOffersNotAllowed { .. } => {
300                fcomponent::Error::InvalidArguments
301            }
302            AddDynamicChildError::ActionError { err } => err.into(),
303            AddDynamicChildError::InvalidDictionary { .. } => fcomponent::Error::InvalidArguments,
304            AddDynamicChildError::StaticRouteConflict { .. } => fcomponent::Error::InvalidArguments,
305            AddDynamicChildError::NameTooLong { .. } => fcomponent::Error::InvalidArguments,
306            // TODO(https://fxbug.dev/297403341): This should become its own error in fidl once
307            // we can introduce it without breaking compatibility.
308            AddDynamicChildError::AddChildError {
309                err:
310                    AddChildError::DynamicCapabilityError { err: DynamicCapabilityError::Cycle { .. } },
311            } => fcomponent::Error::DependencyCycle,
312            AddDynamicChildError::AddChildError {
313                err: AddChildError::DynamicCapabilityError { .. },
314            } => fcomponent::Error::InvalidArguments,
315            AddDynamicChildError::AddChildError { err: AddChildError::ChildNameInvalid { .. } } => {
316                fcomponent::Error::InvalidArguments
317            }
318            AddDynamicChildError::DictionaryAndAdditionalInputsSet => {
319                fcomponent::Error::InvalidArguments
320            }
321        }
322    }
323}
324
325// This is implemented for fuchsia.sys2.LifecycleController protocol
326impl Into<fsys::CreateError> for AddDynamicChildError {
327    fn into(self) -> fsys::CreateError {
328        match self {
329            AddDynamicChildError::CollectionNotFound { .. } => {
330                fsys::CreateError::CollectionNotFound
331            }
332            AddDynamicChildError::AddChildError {
333                err: AddChildError::InstanceAlreadyExists { .. },
334            } => fsys::CreateError::InstanceAlreadyExists,
335
336            AddDynamicChildError::DynamicOffersNotAllowed { .. } => {
337                fsys::CreateError::DynamicOffersForbidden
338            }
339            AddDynamicChildError::ActionError { .. } => fsys::CreateError::Internal,
340            AddDynamicChildError::InvalidDictionary { .. } => fsys::CreateError::Internal,
341            AddDynamicChildError::StaticRouteConflict { .. } => fsys::CreateError::Internal,
342            AddDynamicChildError::NameTooLong { .. } => fsys::CreateError::BadChildDecl,
343            AddDynamicChildError::AddChildError {
344                err: AddChildError::DynamicCapabilityError { .. },
345            } => fsys::CreateError::BadDynamicOffer,
346            AddDynamicChildError::AddChildError { err: AddChildError::ChildNameInvalid { .. } } => {
347                fsys::CreateError::BadMoniker
348            }
349            AddDynamicChildError::NumberedHandleNotInSingleRunCollection => {
350                fsys::CreateError::NumberedHandlesForbidden
351            }
352            AddDynamicChildError::DictionaryAndAdditionalInputsSet => {
353                fsys::CreateError::DictionaryAndAdditionalInputsSet
354            }
355        }
356    }
357}
358
359#[derive(Debug, Error, Clone)]
360pub enum AddChildError {
361    #[error("component instance `{child}` in realm `{moniker}` already exists")]
362    InstanceAlreadyExists { moniker: Moniker, child: ChildName },
363    #[error(transparent)]
364    DynamicCapabilityError {
365        #[from]
366        err: DynamicCapabilityError,
367    },
368    #[error("invalid child name: {err}")]
369    ChildNameInvalid {
370        #[from]
371        err: MonikerError,
372    },
373}
374
375#[derive(Debug, Error, Clone, PartialEq)]
376pub enum DynamicCapabilityError {
377    #[error("a dynamic capability was not valid:\n\t{err}")]
378    Invalid {
379        #[source]
380        err: Box<cm_fidl_validator::error::ErrorList>,
381    },
382    #[error("dynamic offers are not allowed for {typename}")]
383    UnsupportedType { typename: &'static str },
384    #[error("dynamic offer would create a cycle:\n\t{err}")]
385    Cycle {
386        #[source]
387        err: Box<cm_fidl_validator::error::ErrorList>,
388    },
389    #[error("source for dynamic offer not found:\n\t{:?}", offer)]
390    SourceNotFound { offer: cm_rust::offer::OfferDecl },
391    #[error("unknown offer type in dynamic offers")]
392    UnknownOfferType,
393}
394
395#[derive(Debug, Clone, Error)]
396#[error(transparent)]
397pub struct ActionError {
398    kind: Box<ActionErrorKind>,
399}
400
401impl ActionError {
402    pub fn kind(&self) -> &ActionErrorKind {
403        &self.kind
404    }
405}
406
407impl From<ActionErrorKind> for ActionError {
408    fn from(err: ActionErrorKind) -> Self {
409        ActionError { kind: Box::new(err) }
410    }
411}
412
413macro_rules! impl_from_action_error_kind {
414    ($($ty:ty,)+) => {
415        $(
416            impl From<$ty> for ActionError {
417                fn from(err: $ty) -> Self {
418                    ActionError::from(ActionErrorKind::from(err))
419                }
420            }
421        )+
422    }
423}
424
425impl_from_action_error_kind! {
426    DiscoverActionError,
427    ResolveActionError,
428    UnresolveActionError,
429    StartActionError,
430    StopActionError,
431    DestroyActionError,
432    ShutdownActionError,
433}
434
435#[derive(Debug, Clone, Error)]
436pub enum ActionErrorKind {
437    #[error("discover: {err}")]
438    DiscoverError {
439        #[from]
440        err: DiscoverActionError,
441    },
442
443    #[error("resolve: {err}")]
444    ResolveError {
445        #[from]
446        err: ResolveActionError,
447    },
448
449    #[error("unresolve: {err}")]
450    UnresolveError {
451        #[from]
452        err: UnresolveActionError,
453    },
454
455    #[error("start: {err}")]
456    StartError {
457        #[from]
458        err: StartActionError,
459    },
460
461    #[error("stop: {err}")]
462    StopError {
463        #[from]
464        err: StopActionError,
465    },
466
467    #[error("destroy: {err}")]
468    DestroyError {
469        #[from]
470        err: DestroyActionError,
471    },
472
473    #[error("shutdown: {err}")]
474    ShutdownError {
475        #[from]
476        err: ShutdownActionError,
477    },
478}
479
480impl Explain for ActionError {
481    fn as_zx_status(&self) -> zx::Status {
482        match &*self.kind {
483            ActionErrorKind::DiscoverError { .. } => zx::Status::INTERNAL,
484            ActionErrorKind::ResolveError { err } => err.as_zx_status(),
485            ActionErrorKind::UnresolveError { .. } => zx::Status::INTERNAL,
486            ActionErrorKind::StartError { err } => err.as_zx_status(),
487            ActionErrorKind::StopError { .. } => zx::Status::INTERNAL,
488            ActionErrorKind::DestroyError { .. } => zx::Status::INTERNAL,
489            ActionErrorKind::ShutdownError { .. } => zx::Status::INTERNAL,
490        }
491    }
492}
493
494impl From<ActionError> for fcomponent::Error {
495    fn from(err: ActionError) -> Self {
496        match *err.kind {
497            ActionErrorKind::DiscoverError { .. } => fcomponent::Error::Internal,
498            ActionErrorKind::ResolveError { .. } => fcomponent::Error::Internal,
499            ActionErrorKind::UnresolveError { .. } => fcomponent::Error::Internal,
500            ActionErrorKind::StartError { err } => err.into(),
501            ActionErrorKind::StopError { err } => err.into(),
502            ActionErrorKind::DestroyError { err } => err.into(),
503            ActionErrorKind::ShutdownError { .. } => fcomponent::Error::Internal,
504        }
505    }
506}
507
508impl From<ActionError> for fsys::ResolveError {
509    fn from(err: ActionError) -> Self {
510        match *err.kind {
511            ActionErrorKind::ResolveError { err } => err.into(),
512            _ => fsys::ResolveError::Internal,
513        }
514    }
515}
516
517impl From<ActionError> for fsys::UnresolveError {
518    fn from(err: ActionError) -> Self {
519        match *err.kind {
520            ActionErrorKind::UnresolveError { err } => err.into(),
521            _ => fsys::UnresolveError::Internal,
522        }
523    }
524}
525
526impl From<ActionError> for fsys::StartError {
527    fn from(err: ActionError) -> Self {
528        match *err.kind {
529            ActionErrorKind::StartError { err } => err.into(),
530            _ => fsys::StartError::Internal,
531        }
532    }
533}
534
535impl From<ActionError> for fsys::StopError {
536    fn from(err: ActionError) -> Self {
537        match *err.kind {
538            ActionErrorKind::StopError { err } => err.into(),
539            _ => fsys::StopError::Internal,
540        }
541    }
542}
543
544impl From<ActionError> for fsys::DestroyError {
545    fn from(err: ActionError) -> Self {
546        match *err.kind {
547            ActionErrorKind::DestroyError { err } => err.into(),
548            _ => fsys::DestroyError::Internal,
549        }
550    }
551}
552
553#[derive(Debug, Clone, Error)]
554pub enum DiscoverActionError {
555    #[error("`{moniker}` was destroyed")]
556    InstanceDestroyed { moniker: Moniker },
557}
558
559#[derive(Debug, Clone, Error)]
560pub enum ResolveActionError {
561    #[error("discover during resolve: {err}")]
562    DiscoverActionError {
563        #[from]
564        err: DiscoverActionError,
565    },
566    #[error("`{moniker}` was shut down")]
567    InstanceShutDown { moniker: Moniker },
568    #[error("`{moniker}` was destroyed")]
569    InstanceDestroyed { moniker: Moniker },
570    #[error("could not parse component address for `{url}` at `{moniker}`:\n\t{err}")]
571    ComponentAddressParseError {
572        url: Url,
573        moniker: Moniker,
574        #[source]
575        err: Box<ResolverError>,
576    },
577    #[error("resolve failed for `{url}`:\n\t{err}")]
578    ResolverError {
579        url: Url,
580        #[source]
581        err: Box<ResolverError>,
582    },
583    #[error("expose dir for `{moniker}`:\n\t{err}")]
584    // TODO(https://fxbug.dev/42071713): Determine whether this is expected to fail.
585    ExposeDirError {
586        moniker: Moniker,
587
588        #[source]
589        err: VfsError,
590    },
591    #[error("adding static child `{child_name}`:\n\t{err}")]
592    AddStaticChildError {
593        child_name: String,
594        #[source]
595        err: AddChildError,
596    },
597    #[error("structured config: {err}")]
598    StructuredConfigError {
599        #[from]
600        err: StructuredConfigError,
601    },
602    #[error("creating package dir proxy: {err}")]
603    PackageDirProxyCreateError {
604        #[source]
605        err: fidl::Error,
606    },
607    #[error("ABI compatibility check for `{url}`: {err}")]
608    AbiCompatibilityError {
609        url: Url,
610        #[source]
611        err: Box<CompatibilityCheckError>,
612    },
613    #[error(transparent)]
614    Policy(#[from] PolicyError),
615    #[error("`{moniker}` was interrupted")]
616    Aborted { moniker: Moniker },
617}
618
619impl ResolveActionError {
620    fn as_zx_status(&self) -> zx::Status {
621        match self {
622            ResolveActionError::DiscoverActionError { .. }
623            | ResolveActionError::InstanceShutDown { .. }
624            | ResolveActionError::InstanceDestroyed { .. }
625            | ResolveActionError::ComponentAddressParseError { .. }
626            | ResolveActionError::AbiCompatibilityError { .. } => zx::Status::NOT_FOUND,
627            ResolveActionError::ExposeDirError { .. }
628            | ResolveActionError::AddStaticChildError { .. }
629            | ResolveActionError::StructuredConfigError { .. }
630            | ResolveActionError::Aborted { .. }
631            | ResolveActionError::PackageDirProxyCreateError { .. } => zx::Status::INTERNAL,
632            ResolveActionError::ResolverError { err, .. } => err.as_zx_status(),
633            ResolveActionError::Policy(err) => err.as_zx_status(),
634        }
635    }
636}
637
638// This is implemented for fuchsia.sys2.LifecycleController protocol
639impl Into<fsys::ResolveError> for ResolveActionError {
640    fn into(self) -> fsys::ResolveError {
641        match self {
642            ResolveActionError::ResolverError { err, .. } => match *err {
643                ResolverError::PackageNotFound(_) => fsys::ResolveError::PackageNotFound,
644                ResolverError::ManifestNotFound(_) => fsys::ResolveError::ManifestNotFound,
645                _ => fsys::ResolveError::Internal,
646            },
647            ResolveActionError::InstanceShutDown { .. }
648            | ResolveActionError::InstanceDestroyed { .. } => fsys::ResolveError::InstanceNotFound,
649            ResolveActionError::ExposeDirError { .. }
650            | ResolveActionError::StructuredConfigError { .. }
651            | ResolveActionError::ComponentAddressParseError { .. }
652            | ResolveActionError::AddStaticChildError { .. }
653            | ResolveActionError::DiscoverActionError { .. }
654            | ResolveActionError::AbiCompatibilityError { .. }
655            | ResolveActionError::Aborted { .. }
656            | ResolveActionError::PackageDirProxyCreateError { .. } => fsys::ResolveError::Internal,
657            ResolveActionError::Policy(_) => fsys::ResolveError::PolicyError,
658        }
659    }
660}
661
662// This is implemented for fuchsia.sys2.LifecycleController protocol.
663// Starting a component instance also causes a resolve.
664impl Into<fsys::StartError> for ResolveActionError {
665    fn into(self) -> fsys::StartError {
666        match self {
667            ResolveActionError::ResolverError { err, .. } => match *err {
668                ResolverError::PackageNotFound(_) => fsys::StartError::PackageNotFound,
669                ResolverError::ManifestNotFound(_) => fsys::StartError::ManifestNotFound,
670                _ => fsys::StartError::Internal,
671            },
672            ResolveActionError::InstanceShutDown { .. }
673            | ResolveActionError::InstanceDestroyed { .. } => fsys::StartError::InstanceNotFound,
674            ResolveActionError::ExposeDirError { .. }
675            | ResolveActionError::StructuredConfigError { .. }
676            | ResolveActionError::ComponentAddressParseError { .. }
677            | ResolveActionError::AddStaticChildError { .. }
678            | ResolveActionError::DiscoverActionError { .. }
679            | ResolveActionError::AbiCompatibilityError { .. }
680            | ResolveActionError::Aborted { .. }
681            | ResolveActionError::PackageDirProxyCreateError { .. } => fsys::StartError::Internal,
682            ResolveActionError::Policy(_) => fsys::StartError::PolicyError,
683        }
684    }
685}
686
687#[derive(Debug, Clone, Error)]
688pub enum PkgDirError {
689    #[error("no pkg dir found for component")]
690    NoPkgDir,
691    #[error("opening pkg dir failed: {err}")]
692    OpenFailed {
693        #[from]
694        err: zx::Status,
695    },
696}
697
698impl PkgDirError {
699    fn as_zx_status(&self) -> zx::Status {
700        match self {
701            Self::NoPkgDir => zx::Status::NOT_FOUND,
702            Self::OpenFailed { err } => *err,
703        }
704    }
705}
706
707#[derive(Debug, Clone, Error)]
708pub enum ComponentProviderError {
709    #[error("starting source instance:\n\t{err}")]
710    SourceStartError {
711        #[from]
712        err: ActionError,
713    },
714    #[error("opening source instance's outgoing dir:\n\t{err}")]
715    OpenOutgoingDirError {
716        #[from]
717        err: OpenOutgoingDirError,
718    },
719}
720
721impl ComponentProviderError {
722    pub fn as_zx_status(&self) -> zx::Status {
723        match self {
724            Self::SourceStartError { err } => err.as_zx_status(),
725            Self::OpenOutgoingDirError { err } => err.as_zx_status(),
726        }
727    }
728}
729
730#[derive(Debug, Clone, Error)]
731pub enum CapabilityProviderError {
732    #[error("bad path")]
733    BadPath,
734    #[error(transparent)]
735    ComponentInstanceError {
736        #[from]
737        err: ComponentInstanceError,
738    },
739    #[error(transparent)]
740    PkgDirError {
741        #[from]
742        err: PkgDirError,
743    },
744    #[error("event source: {0}")]
745    EventSourceError(#[from] EventSourceError),
746    #[error(transparent)]
747    ComponentProviderError {
748        #[from]
749        err: ComponentProviderError,
750    },
751    #[error("component_manager namespace: {err}")]
752    CmNamespaceError {
753        #[from]
754        err: ClonableError,
755    },
756    #[error("router: {err}")]
757    RouterError {
758        #[from]
759        err: RouterError,
760    },
761    #[error(transparent)]
762    RoutingError(#[from] RoutingError),
763    #[error("opening vfs failed: {0}")]
764    VfsOpenError(#[source] zx::Status),
765}
766
767impl CapabilityProviderError {
768    pub fn as_zx_status(&self) -> zx::Status {
769        match self {
770            Self::BadPath => zx::Status::INVALID_ARGS,
771            Self::ComponentInstanceError { err } => err.as_zx_status(),
772            Self::CmNamespaceError { .. } => zx::Status::INTERNAL,
773            Self::PkgDirError { err } => err.as_zx_status(),
774            Self::EventSourceError(err) => err.as_zx_status(),
775            Self::ComponentProviderError { err } => err.as_zx_status(),
776            Self::RouterError { err } => err.as_zx_status(),
777            Self::RoutingError(err) => err.as_zx_status(),
778            Self::VfsOpenError(err) => *err,
779        }
780    }
781}
782
783#[derive(Debug, Clone, Error)]
784pub enum OpenError {
785    #[error("failed to get default capability provider: {err}")]
786    GetDefaultProviderError {
787        // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
788        #[source]
789        err: Box<ModelError>,
790    },
791    #[error("no capability provider found")]
792    CapabilityProviderNotFound,
793    #[error("capability provider: {err}")]
794    CapabilityProviderError {
795        #[from]
796        err: CapabilityProviderError,
797    },
798    #[error("opening storage capability: {err}")]
799    OpenStorageError {
800        // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
801        #[source]
802        err: Box<ModelError>,
803    },
804    #[error("timed out opening capability")]
805    Timeout,
806    #[error("invalid path found")]
807    BadPath,
808    #[error("capability does not support opening: {0}")]
809    DoesNotSupportOpen(ConversionError),
810    #[error("failed to create directory watcher: {err}")]
811    WatcherCreateError {
812        #[from]
813        err: WatcherCreateError,
814    },
815}
816
817impl Explain for OpenError {
818    fn as_zx_status(&self) -> zx::Status {
819        match self {
820            Self::GetDefaultProviderError { err } => err.as_zx_status(),
821            Self::OpenStorageError { err } => err.as_zx_status(),
822            Self::CapabilityProviderError { err } => err.as_zx_status(),
823            Self::CapabilityProviderNotFound => zx::Status::NOT_FOUND,
824            Self::Timeout => zx::Status::TIMED_OUT,
825            Self::BadPath => zx::Status::BAD_PATH,
826            Self::DoesNotSupportOpen(_) => zx::Status::NOT_SUPPORTED,
827            Self::WatcherCreateError { err: WatcherCreateError::SendWatchRequest(_err) } => {
828                zx::Status::PEER_CLOSED
829            }
830            Self::WatcherCreateError { err: WatcherCreateError::WatchError(status) } => *status,
831            Self::WatcherCreateError { err: WatcherCreateError::ChannelConversion(status) } => {
832                *status
833            }
834        }
835    }
836}
837
838impl From<OpenError> for RouterError {
839    fn from(value: OpenError) -> Self {
840        Self::NotFound(Arc::new(value))
841    }
842}
843
844#[derive(Debug, Clone, Error)]
845pub enum StartActionError {
846    #[error("`{moniker}` was shut down")]
847    InstanceShutDown { moniker: Moniker },
848    #[error("`{moniker}` was destroyed")]
849    InstanceDestroyed { moniker: Moniker },
850    #[error("`{moniker}` couldn't resolve during start: {err}")]
851    ResolveActionError {
852        moniker: Moniker,
853        #[source]
854        err: Box<ActionError>,
855    },
856    #[error("runner for `{moniker}` `{runner}` couldn't resolve: {err}")]
857    ResolveRunnerError {
858        moniker: Moniker,
859        runner: Name,
860        #[source]
861        err: Box<RouterError>,
862    },
863    #[error(
864        "`{moniker}` uses `\"on_terminate\": \"reboot\"` but is disallowed by policy:\n\t{err}"
865    )]
866    RebootOnTerminateForbidden {
867        moniker: Moniker,
868        #[source]
869        err: PolicyError,
870    },
871    #[error("creating program input dictionary for `{moniker}`")]
872    InputDictionaryError { moniker: Moniker },
873    #[error("creating namespace: {0}")]
874    CreateNamespaceError(#[from] CreateNamespaceError),
875    #[error("starting program for `{moniker}`: {err}")]
876    StartProgramError {
877        moniker: Moniker,
878        #[source]
879        err: StartError,
880    },
881    #[error("structured configuration for `{moniker}`: {err}")]
882    StructuredConfigError {
883        moniker: Moniker,
884        #[source]
885        err: StructuredConfigError,
886    },
887    #[error("starting eager child of `{moniker}`: {err}")]
888    EagerStartError {
889        moniker: Moniker,
890        #[source]
891        err: Box<ActionError>,
892    },
893    #[error("`{moniker}` was interrupted")]
894    Aborted { moniker: Moniker },
895}
896
897impl StartActionError {
898    fn as_zx_status(&self) -> zx::Status {
899        match self {
900            StartActionError::InstanceDestroyed { .. } | Self::InstanceShutDown { .. } => {
901                zx::Status::NOT_FOUND
902            }
903            StartActionError::StartProgramError { .. }
904            | StartActionError::StructuredConfigError { .. }
905            | StartActionError::EagerStartError { .. } => zx::Status::INTERNAL,
906            StartActionError::RebootOnTerminateForbidden { err, .. } => err.as_zx_status(),
907            StartActionError::ResolveRunnerError { err, .. } => err.as_zx_status(),
908            StartActionError::CreateNamespaceError(err) => err.as_zx_status(),
909            StartActionError::InputDictionaryError { .. } => zx::Status::NOT_FOUND,
910            StartActionError::ResolveActionError { err, .. } => err.as_zx_status(),
911            StartActionError::Aborted { .. } => zx::Status::NOT_FOUND,
912        }
913    }
914}
915
916// This is implemented for fuchsia.sys2.LifecycleController protocol.
917impl Into<fsys::StartError> for StartActionError {
918    fn into(self) -> fsys::StartError {
919        match self {
920            StartActionError::ResolveActionError { err, .. } => (*err).into(),
921            StartActionError::InstanceDestroyed { .. } => fsys::StartError::InstanceNotFound,
922            StartActionError::InstanceShutDown { .. } => fsys::StartError::InstanceNotFound,
923            _ => fsys::StartError::Internal,
924        }
925    }
926}
927
928// This is implemented for fuchsia.component.Realm protocol.
929impl Into<fcomponent::Error> for StartActionError {
930    fn into(self) -> fcomponent::Error {
931        match self {
932            StartActionError::ResolveActionError { .. } => fcomponent::Error::InstanceCannotResolve,
933            StartActionError::RebootOnTerminateForbidden { .. } => fcomponent::Error::AccessDenied,
934            StartActionError::InstanceShutDown { .. } => fcomponent::Error::InstanceDied,
935            StartActionError::InstanceDestroyed { .. } => fcomponent::Error::InstanceDied,
936            _ => fcomponent::Error::InstanceCannotStart,
937        }
938    }
939}
940
941#[derive(Debug, Clone, Error)]
942pub enum StopActionError {
943    #[error("stopping program: {0}")]
944    ProgramStopError(#[source] StopError),
945    #[error("failed to get top instance")]
946    GetTopInstanceFailed,
947    #[error("failed to get parent instance")]
948    GetParentFailed,
949    #[error("failed to destroy dynamic children: {err}")]
950    DestroyDynamicChildrenFailed { err: Box<ActionError> },
951    #[error("resolution during stop: {err}")]
952    ResolveActionError {
953        #[source]
954        err: Box<ActionError>,
955    },
956    #[error("started while shutdown was ongoing")]
957    ComponentStartedDuringShutdown,
958}
959
960// This is implemented for fuchsia.sys2.LifecycleController protocol.
961impl Into<fsys::StopError> for StopActionError {
962    fn into(self) -> fsys::StopError {
963        fsys::StopError::Internal
964    }
965}
966
967impl Into<fcomponent::Error> for StopActionError {
968    fn into(self) -> fcomponent::Error {
969        fcomponent::Error::Internal
970    }
971}
972
973#[cfg(test)]
974impl PartialEq for StopActionError {
975    fn eq(&self, other: &Self) -> bool {
976        match (self, other) {
977            (StopActionError::ProgramStopError(_), StopActionError::ProgramStopError(_)) => true,
978            (StopActionError::GetTopInstanceFailed, StopActionError::GetTopInstanceFailed) => true,
979            (StopActionError::GetParentFailed, StopActionError::GetParentFailed) => true,
980            (
981                StopActionError::DestroyDynamicChildrenFailed { .. },
982                StopActionError::DestroyDynamicChildrenFailed { .. },
983            ) => true,
984            (
985                StopActionError::ResolveActionError { .. },
986                StopActionError::ResolveActionError { .. },
987            ) => true,
988            _ => false,
989        }
990    }
991}
992
993#[derive(Debug, Clone, Error)]
994pub enum ShutdownActionError {
995    #[error("child name invalid: {}", err)]
996    InvalidChildName {
997        #[from]
998        err: MonikerError,
999    },
1000    #[error("cycles detected in graph")]
1001    CyclesDetected {},
1002}
1003
1004#[derive(Debug, Clone, Error)]
1005pub enum DestroyActionError {
1006    #[error("discover during destroy: {}", err)]
1007    DiscoverActionError {
1008        #[from]
1009        err: DiscoverActionError,
1010    },
1011    #[error("shutdown during destroy: {}", err)]
1012    ShutdownFailed {
1013        #[source]
1014        err: Box<ActionError>,
1015    },
1016    #[error("could not find `{moniker}`")]
1017    InstanceNotFound { moniker: Moniker },
1018    #[error("`{moniker}` is not resolved")]
1019    InstanceNotResolved { moniker: Moniker },
1020}
1021
1022// This is implemented for fuchsia.component.Realm protocol.
1023impl Into<fcomponent::Error> for DestroyActionError {
1024    fn into(self) -> fcomponent::Error {
1025        match self {
1026            DestroyActionError::InstanceNotFound { .. } => fcomponent::Error::InstanceNotFound,
1027            _ => fcomponent::Error::Internal,
1028        }
1029    }
1030}
1031
1032// This is implemented for fuchsia.sys2.LifecycleController protocol.
1033impl Into<fsys::DestroyError> for DestroyActionError {
1034    fn into(self) -> fsys::DestroyError {
1035        match self {
1036            DestroyActionError::InstanceNotFound { .. } => fsys::DestroyError::InstanceNotFound,
1037            DestroyActionError::InstanceNotResolved { .. } => {
1038                fsys::DestroyError::InstanceNotResolved
1039            }
1040            _ => fsys::DestroyError::Internal,
1041        }
1042    }
1043}
1044
1045#[derive(Debug, Clone, Error)]
1046pub enum UnresolveActionError {
1047    #[error("shutdown during unresolve: {err}")]
1048    ShutdownFailed {
1049        #[from]
1050        err: StopActionError,
1051    },
1052    #[error("`{moniker}` cannot be unresolved while it is running")]
1053    InstanceRunning { moniker: Moniker },
1054    #[error("`{moniker}` was destroyed")]
1055    InstanceDestroyed { moniker: Moniker },
1056}
1057
1058// This is implemented for fuchsia.sys2.LifecycleController protocol.
1059impl Into<fsys::UnresolveError> for UnresolveActionError {
1060    fn into(self) -> fsys::UnresolveError {
1061        match self {
1062            UnresolveActionError::InstanceDestroyed { .. } => {
1063                fsys::UnresolveError::InstanceNotFound
1064            }
1065            _ => fsys::UnresolveError::Internal,
1066        }
1067    }
1068}
1069
1070#[derive(Debug, Clone, Error)]
1071pub enum CreateNamespaceError {
1072    #[error("failed to clone pkg dir for {moniker}: {err}")]
1073    ClonePkgDirFailed {
1074        moniker: Moniker,
1075        #[source]
1076        err: fuchsia_fs::node::CloneError,
1077    },
1078
1079    #[error("use decl without path cannot be installed into the namespace for {moniker}: {decl:?}")]
1080    UseDeclWithoutPath { moniker: Moniker, decl: UseDecl },
1081
1082    #[error("instance not in index: {0}")]
1083    InstanceNotInInstanceIdIndex(#[from] RoutingError),
1084
1085    #[error("building namespace for {moniker}: {err}")]
1086    BuildNamespaceError {
1087        moniker: Moniker,
1088        #[source]
1089        err: serve_processargs::BuildNamespaceError,
1090    },
1091
1092    #[error("failed to convert namespace into directory for {moniker}: {err}")]
1093    ConvertToDirectory {
1094        moniker: Moniker,
1095        #[source]
1096        err: ClonableError,
1097    },
1098
1099    #[error(transparent)]
1100    ComponentInstanceError(#[from] ComponentInstanceError),
1101}
1102
1103impl CreateNamespaceError {
1104    fn as_zx_status(&self) -> zx::Status {
1105        match self {
1106            Self::ClonePkgDirFailed { .. } => zx::Status::INTERNAL,
1107            Self::UseDeclWithoutPath { .. } => zx::Status::NOT_FOUND,
1108            Self::InstanceNotInInstanceIdIndex(err) => err.as_zx_status(),
1109            Self::BuildNamespaceError { .. } => zx::Status::NOT_FOUND,
1110            Self::ConvertToDirectory { .. } => zx::Status::INTERNAL,
1111            Self::ComponentInstanceError(err) => err.as_zx_status(),
1112        }
1113    }
1114}
1115
1116#[derive(Debug, Clone, Error)]
1117pub enum EventSourceError {
1118    #[error(transparent)]
1119    ComponentInstance(#[from] ComponentInstanceError),
1120    #[error(transparent)]
1121    // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
1122    Model(#[from] Box<ModelError>),
1123    #[error("event stream already consumed")]
1124    AlreadyConsumed,
1125}
1126
1127impl EventSourceError {
1128    fn as_zx_status(&self) -> zx::Status {
1129        match self {
1130            Self::ComponentInstance(err) => err.as_zx_status(),
1131            Self::Model(err) => err.as_zx_status(),
1132            Self::AlreadyConsumed => zx::Status::INTERNAL,
1133        }
1134    }
1135}
1136
1137#[derive(Debug, Error, Clone)]
1138pub enum EventsError {
1139    #[error("capability_requested event streams cannot be taken twice")]
1140    CapabilityRequestedStreamTaken,
1141
1142    #[error("model not available")]
1143    ModelNotAvailable,
1144
1145    #[error("instance shut down")]
1146    InstanceShutdown,
1147
1148    #[error("instance destroyed")]
1149    InstanceDestroyed,
1150
1151    #[error("registry not found")]
1152    RegistryNotFound,
1153
1154    #[error("event `{event_name}` appears more than once in a subscription request")]
1155    DuplicateEvent { event_name: Name },
1156
1157    #[error("events not available for subscription: `{names:?}`")]
1158    NotAvailable { names: Vec<Name> },
1159}
1160
1161impl EventsError {
1162    pub fn duplicate_event(event_name: Name) -> Self {
1163        Self::DuplicateEvent { event_name }
1164    }
1165
1166    pub fn not_available(names: Vec<Name>) -> Self {
1167        Self::NotAvailable { names }
1168    }
1169}
1170
1171/// Errors related to isolated storage.
1172#[derive(Debug, Error, Clone)]
1173pub enum StorageError {
1174    #[error("opening directory from `{dir_source_moniker:?}` at `{dir_source_path}`:\n\t{err}")]
1175    OpenRoot {
1176        dir_source_moniker: Option<Moniker>,
1177        dir_source_path: cm_types::Path,
1178        #[source]
1179        err: ClonableError,
1180    },
1181    #[error(
1182        "opening isolated storage from `{dir_source_moniker:?}`'s for `{moniker}` at `{dir_source_path}` (instance_id={instance_id:?}):\n\t{err}"
1183    )]
1184    Open {
1185        dir_source_moniker: Option<Moniker>,
1186        dir_source_path: cm_types::Path,
1187        moniker: Moniker,
1188        instance_id: Option<InstanceId>,
1189        #[source]
1190        err: ClonableError,
1191    },
1192    #[error(
1193        "opening isolated storage from `{dir_source_moniker:?}` at `{dir_source_path}` for {instance_id}:\n\t{err}"
1194    )]
1195    OpenById {
1196        dir_source_moniker: Option<Moniker>,
1197        dir_source_path: cm_types::Path,
1198        instance_id: InstanceId,
1199        #[source]
1200        err: ClonableError,
1201    },
1202    #[error(
1203        "removing isolated storage from {dir_source_moniker:?} at `{dir_source_path}` for `{moniker}` (instance_id={instance_id:?}):n\t{err} "
1204    )]
1205    Remove {
1206        dir_source_moniker: Option<Moniker>,
1207        dir_source_path: cm_types::Path,
1208        moniker: Moniker,
1209        instance_id: Option<InstanceId>,
1210        #[source]
1211        err: ClonableError,
1212    },
1213    #[error("storage path for `{moniker}` (instance_id={instance_id:?}) is invalid")]
1214    InvalidStoragePath { moniker: Moniker, instance_id: Option<InstanceId> },
1215}
1216
1217impl StorageError {
1218    pub fn open_root(
1219        dir_source_moniker: Option<Moniker>,
1220        dir_source_path: cm_types::Path,
1221        err: impl Into<Error>,
1222    ) -> Self {
1223        Self::OpenRoot { dir_source_moniker, dir_source_path, err: err.into().into() }
1224    }
1225
1226    pub fn open(
1227        dir_source_moniker: Option<Moniker>,
1228        dir_source_path: cm_types::Path,
1229        moniker: Moniker,
1230        instance_id: Option<InstanceId>,
1231        err: impl Into<Error>,
1232    ) -> Self {
1233        Self::Open {
1234            dir_source_moniker,
1235            dir_source_path,
1236            moniker,
1237            instance_id,
1238            err: err.into().into(),
1239        }
1240    }
1241
1242    pub fn open_by_id(
1243        dir_source_moniker: Option<Moniker>,
1244        dir_source_path: cm_types::Path,
1245        instance_id: InstanceId,
1246        err: impl Into<Error>,
1247    ) -> Self {
1248        Self::OpenById { dir_source_moniker, dir_source_path, instance_id, err: err.into().into() }
1249    }
1250
1251    pub fn remove(
1252        dir_source_moniker: Option<Moniker>,
1253        dir_source_path: cm_types::Path,
1254        moniker: Moniker,
1255        instance_id: Option<InstanceId>,
1256        err: impl Into<Error>,
1257    ) -> Self {
1258        Self::Remove {
1259            dir_source_moniker,
1260            dir_source_path,
1261            moniker,
1262            instance_id,
1263            err: err.into().into(),
1264        }
1265    }
1266
1267    pub fn invalid_storage_path(moniker: Moniker, instance_id: Option<InstanceId>) -> Self {
1268        Self::InvalidStoragePath { moniker, instance_id }
1269    }
1270}
1271
1272#[derive(Error, Debug, Clone)]
1273pub enum StartError {
1274    #[error("serving namespace: {0}")]
1275    ServeNamespace(BuildNamespaceError),
1276}
1277
1278#[derive(Error, Debug, Clone)]
1279pub enum StopError {
1280    /// Internal errors are not meant to be meaningfully handled by the user.
1281    #[error("internal: {0}")]
1282    Internal(fidl::Error),
1283}