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