Skip to main content

openmls/group/
errors.rs

1//! # MLS group errors
2//!
3//! This module contains errors that originate at lower levels and are partially re-exported in errors thrown by functions of the `MlsGroup` API.
4
5use thiserror::Error;
6
7#[cfg(feature = "extensions-draft-08")]
8use super::public_group::errors::ApplyAppDataUpdateError;
9
10pub use super::mls_group::errors::*;
11use super::public_group::errors::CreationFromExternalError;
12use crate::{
13    ciphersuite::signable::SignatureError,
14    error::LibraryError,
15    extensions::errors::{ExtensionError, InvalidExtensionError},
16    framing::errors::MessageDecryptionError,
17    group::commit_builder::external_commits::ExternalCommitBuilderError,
18    key_packages::errors::{KeyPackageExtensionSupportError, KeyPackageVerifyError},
19    messages::{group_info::GroupInfoError, GroupSecretsError},
20    prelude::ExtensionType,
21    schedule::{errors::PskError, PreSharedKeyId},
22    treesync::errors::*,
23};
24
25#[cfg(doc)]
26use crate::{group::GroupId, treesync::LeafNodeParameters};
27
28/// Welcome error
29#[derive(Error, Debug, PartialEq, Clone)]
30pub enum WelcomeError<StorageError> {
31    /// See [`GroupSecretsError`] for more details.
32    #[error(transparent)]
33    GroupSecrets(#[from] GroupSecretsError),
34    /// Private part of `init_key` not found in key store.
35    #[error("Private part of `init_key` not found in key store.")]
36    PrivateInitKeyNotFound,
37    /// See [`LibraryError`] for more details.
38    #[error(transparent)]
39    LibraryError(#[from] LibraryError),
40    /// Ciphersuites in Welcome and key package bundle don't match.
41    #[error("Ciphersuites in Welcome and key package bundle don't match.")]
42    CiphersuiteMismatch,
43    /// See [`GroupInfoError`] for more details.
44    #[error(transparent)]
45    GroupInfo(#[from] GroupInfoError),
46    /// No joiner secret found in the Welcome message.
47    #[error("No joiner secret found in the Welcome message.")]
48    JoinerSecretNotFound,
49    /// No ratchet tree available to build initial tree after receiving a Welcome message.
50    #[error("No ratchet tree available to build initial tree after receiving a Welcome message.")]
51    MissingRatchetTree,
52    /// The computed confirmation tag does not match the expected one.
53    #[error("The computed confirmation tag does not match the expected one.")]
54    ConfirmationTagMismatch,
55    /// The signature on the GroupInfo is not valid.
56    #[error("The signature on the GroupInfo is not valid.")]
57    InvalidGroupInfoSignature,
58    /// We don't support the version of the group we are trying to join.
59    #[error("We don't support the version of the group we are trying to join.")]
60    UnsupportedMlsVersion,
61    /// We don't support all capabilities of the group.
62    #[error("We don't support all capabilities of the group.")]
63    UnsupportedCapability,
64    /// Sender not found in tree.
65    #[error("Sender not found in tree.")]
66    UnknownSender,
67    /// The provided message is not a Welcome message.
68    #[error("Not a Welcome message.")]
69    NotAWelcomeMessage,
70    /// Malformed Welcome message.
71    #[error("Malformed Welcome message.")]
72    MalformedWelcomeMessage,
73    /// Could not decrypt the Welcome message.
74    #[error("Could not decrypt the Welcome message.")]
75    UnableToDecrypt,
76    /// Unsupported extensions found in the GroupContext or KeyPackage of another member.
77    #[error("Unsupported extensions found in the GroupContext or KeyPackage of another member.")]
78    UnsupportedExtensions,
79    /// See [`PskError`] for more details.
80    #[error(transparent)]
81    Psk(#[from] PskError),
82    /// No matching encryption key was found in the key store.
83    #[error("No matching encryption key was found in the key store.")]
84    NoMatchingEncryptionKey,
85    /// No matching key package was found in the key store.
86    #[error("No matching key package was found in the key store.")]
87    NoMatchingKeyPackage,
88    /// This error indicates the public tree is invalid. See [`PublicTreeError`] for more details.
89    #[error(transparent)]
90    PublicTreeError(#[from] PublicTreeError),
91    /// This error indicates the public tree is invalid. See
92    /// [`CreationFromExternalError`] for more details.
93    #[error(transparent)]
94    PublicGroupError(#[from] CreationFromExternalError<StorageError>),
95    /// This error indicates the leaf node is invalid. See [`LeafNodeValidationError`] for more details.
96    #[error(transparent)]
97    LeafNodeValidation(#[from] LeafNodeValidationError),
98    /// This error indicates that an error occurred while reading or writing from/to storage.
99    #[error("An error occurred when querying storage")]
100    StorageError(StorageError),
101    /// A group with this [`GroupId`] already exists.
102    #[error("A group with this [`GroupId`] already exists.")]
103    GroupAlreadyExists,
104}
105
106/// External Commit error
107#[derive(Error, Debug, PartialEq, Clone)]
108pub enum ExternalCommitError<StorageError> {
109    /// See [`LibraryError`] for more details.
110    #[error(transparent)]
111    LibraryError(#[from] LibraryError),
112    /// No ratchet tree available to build initial tree.
113    #[error("No ratchet tree available to build initial tree.")]
114    MissingRatchetTree,
115    /// No external_pub extension available to join group by external commit.
116    #[error("No external_pub extension available to join group by external commit.")]
117    MissingExternalPub,
118    /// We don't support the ciphersuite of the group we are trying to join.
119    #[error("We don't support the ciphersuite of the group we are trying to join.")]
120    UnsupportedCiphersuite,
121    /// Sender not found in tree.
122    #[error("Sender not found in tree.")]
123    UnknownSender,
124    /// The signature over the given group info is invalid.
125    #[error("The signature over the given group info is invalid.")]
126    InvalidGroupInfoSignature,
127    /// Error creating external commit.
128    #[error("Error creating external commit.")]
129    CommitError(#[from] CreateCommitError),
130    /// This error indicates the public tree is invalid. See
131    /// [`CreationFromExternalError`] for more details.
132    #[error(transparent)]
133    PublicGroupError(#[from] CreationFromExternalError<StorageError>),
134    /// Credential is missing from external commit.
135    #[error("Credential is missing from external commit.")]
136    MissingCredential,
137    /// An erorr occurred when writing group to storage
138    #[error("An error occurred when writing group to storage.")]
139    StorageError(StorageError),
140}
141
142impl<StorageError> From<ExternalCommitBuilderError<StorageError>>
143    for ExternalCommitError<StorageError>
144{
145    fn from(error: ExternalCommitBuilderError<StorageError>) -> Self {
146        match error {
147            ExternalCommitBuilderError::LibraryError(library_error) => {
148                ExternalCommitError::LibraryError(library_error)
149            }
150            ExternalCommitBuilderError::MissingRatchetTree => {
151                ExternalCommitError::MissingRatchetTree
152            }
153            ExternalCommitBuilderError::MissingExternalPub => {
154                ExternalCommitError::MissingExternalPub
155            }
156            ExternalCommitBuilderError::UnsupportedCiphersuite => {
157                ExternalCommitError::UnsupportedCiphersuite
158            }
159            ExternalCommitBuilderError::PublicGroupError(creation_from_external_error) => {
160                ExternalCommitError::PublicGroupError(creation_from_external_error)
161            }
162            ExternalCommitBuilderError::StorageError(error) => {
163                ExternalCommitError::StorageError(error)
164            }
165            // These should not happen since `join_by_external_commit` doesn't
166            // take proposals as input.
167            ExternalCommitBuilderError::InvalidProposal(e) => {
168                log::error!("Error validating proposal in external commit: {e}");
169                ExternalCommitError::LibraryError(LibraryError::custom(
170                    "Error creating external commit",
171                ))
172            }
173        }
174    }
175}
176
177impl<StorageError> From<ExternalCommitBuilderFinalizeError<StorageError>>
178    for ExternalCommitError<StorageError>
179{
180    fn from(error: ExternalCommitBuilderFinalizeError<StorageError>) -> Self {
181        match error {
182            ExternalCommitBuilderFinalizeError::LibraryError(library_error) => {
183                ExternalCommitError::LibraryError(library_error)
184            }
185            ExternalCommitBuilderFinalizeError::StorageError(error) => {
186                ExternalCommitError::StorageError(error)
187            }
188            ExternalCommitBuilderFinalizeError::MergeCommitError(e) => {
189                log::error!("Error merging external commit: {e}");
190                // This shouldn't happen, since we merge our own external
191                // commit.
192                ExternalCommitError::LibraryError(LibraryError::custom(
193                    "Error merging external commit",
194                ))
195            }
196        }
197    }
198}
199
200/// Stage Commit error
201#[derive(Error, Debug, PartialEq, Clone)]
202pub enum StageCommitError {
203    /// See [`LibraryError`] for more details.
204    #[error(transparent)]
205    LibraryError(#[from] LibraryError),
206    /// The epoch of the group context and PublicMessage didn't match.
207    #[error("The epoch of the group context and PublicMessage didn't match.")]
208    EpochMismatch,
209    /// The Commit was created by this client.
210    #[error("The Commit was created by this client.")]
211    OwnCommit,
212    /// stage_commit was called with an PublicMessage that is not a Commit.
213    #[error("stage_commit was called with an PublicMessage that is not a Commit.")]
214    WrongPlaintextContentType,
215    /// Unable to verify the leaf node signature.
216    #[error("Unable to verify the leaf node signature.")]
217    PathLeafNodeVerificationFailure,
218    /// Unable to determine commit path.
219    #[error("Unable to determine commit path.")]
220    RequiredPathNotFound,
221    /// The confirmation Tag is missing.
222    #[error("The confirmation Tag is missing.")]
223    ConfirmationTagMissing,
224    /// The confirmation tag is invalid.
225    #[error("The confirmation tag is invalid.")]
226    ConfirmationTagMismatch,
227    /// The committer can't remove themselves.
228    #[error("The committer can't remove themselves.")]
229    AttemptedSelfRemoval,
230    /// The proposal queue is missing a proposal for the commit.
231    #[error("The proposal queue is missing a proposal for the commit.")]
232    MissingProposal,
233    /// Missing own key to apply proposal.
234    #[error("Missing own key to apply proposal.")]
235    OwnKeyNotFound,
236    /// External Committer used the wrong index.
237    #[error("External Committer used the wrong index.")]
238    InconsistentSenderIndex,
239    /// The sender is of type external, which is not valid.
240    #[error("The sender is of type external, which is not valid.")]
241    SenderTypeExternal,
242    /// The sender is of type `NewMemberProposal`, which is not valid.
243    #[error("The sender is of type NewMemberProposal, which is not valid.")]
244    SenderTypeNewMemberProposal,
245    /// Too many new members: the tree is full.
246    #[error("Too many new members: the tree is full.")]
247    TooManyNewMembers,
248    /// See [`ProposalValidationError`] for more details.
249    #[error(transparent)]
250    ProposalValidationError(#[from] ProposalValidationError),
251    /// See [`PskError`] for more details.
252    #[error(transparent)]
253    PskError(#[from] PskError),
254    /// See [`ExternalCommitValidationError`] for more details.
255    #[error(transparent)]
256    ExternalCommitValidation(#[from] ExternalCommitValidationError),
257    /// See [`ApplyUpdatePathError`] for more details.
258    #[error(transparent)]
259    UpdatePathError(#[from] ApplyUpdatePathError),
260    /// Missing decryption key.
261    #[error("Missing decryption key.")]
262    MissingDecryptionKey,
263    /// See [`UpdatePathError`] for more details.
264    #[error(transparent)]
265    VerifiedUpdatePathError(#[from] UpdatePathError),
266    /// See [`GroupContextExtensionsProposalValidationError`] for more details.
267    #[error(transparent)]
268    GroupContextExtensionsProposalValidationError(
269        #[from] GroupContextExtensionsProposalValidationError,
270    ),
271    #[cfg(feature = "extensions-draft-08")]
272    /// See [`AppDataUpdateValidationError`] for more details.
273    #[error(transparent)]
274    AppDataUpdateValidationError(#[from] AppDataUpdateValidationError),
275    /// See [`LeafNodeValidationError`] for more details.
276    #[error(transparent)]
277    LeafNodeValidation(#[from] LeafNodeValidationError),
278    /// See [`ApplyAppDataUpdateError`] for more details.
279    #[cfg(feature = "extensions-draft-08")]
280    #[error(transparent)]
281    ApplyAppDataUpdateError(#[from] ApplyAppDataUpdateError),
282    /// Duplicate PSK Proposal.
283    #[error("Duplicate PSK proposal with PSK ID {0:?}.")]
284    DuplicatePskId(PreSharedKeyId),
285}
286
287/// Create commit error
288#[derive(Error, Debug, PartialEq, Clone)]
289pub enum CreateCommitError {
290    /// See [`LibraryError`] for more details.
291    #[error(transparent)]
292    LibraryError(#[from] LibraryError),
293    /// Missing own key to apply proposal.
294    #[error("Missing own key to apply proposal.")]
295    OwnKeyNotFound,
296    /// The Commit tried to remove self from the group. This is not possible.
297    #[error("The Commit tried to remove self from the group. This is not possible.")]
298    CannotRemoveSelf,
299    /// The proposal queue is missing a proposal for the commit.
300    #[error("The proposal queue is missing a proposal for the commit.")]
301    MissingProposal,
302    /// A proposal has the wrong sender type.
303    #[error("A proposal has the wrong sender type.")]
304    WrongProposalSenderType,
305    /// See [`PskError`] for more details.
306    #[error(transparent)]
307    PskError(#[from] PskError),
308    /// See [`ProposalValidationError`] for more details.
309    #[error(transparent)]
310    ProposalValidationError(#[from] ProposalValidationError),
311    /// See [`SignatureError`] for more details.
312    #[error(transparent)]
313    SignatureError(#[from] SignatureError),
314    /// Credential is missing from external commit.
315    #[error("Credential is missing from external commit.")]
316    MissingCredential,
317    /// This error indicates the public tree is invalid. See [`PublicTreeError`] for more details.
318    #[error(transparent)]
319    PublicTreeError(#[from] PublicTreeError),
320    /// See [`InvalidExtensionError`] for more details.
321    #[error(transparent)]
322    InvalidExtensionError(#[from] InvalidExtensionError),
323    #[cfg(feature = "extensions-draft-08")]
324    /// See [`AppDataUpdateValidationError`] for more details.
325    #[error(transparent)]
326    AppDataUpdateValidationError(#[from] AppDataUpdateValidationError),
327    /// See [`GroupContextExtensionsProposalValidationError`] for more details.
328    #[error(transparent)]
329    GroupContextExtensionsProposalValidationError(
330        #[from] GroupContextExtensionsProposalValidationError,
331    ),
332    /// See [`TreeSyncAddLeaf`] for more details.
333    #[error(transparent)]
334    TreeSyncAddLeaf(#[from] TreeSyncAddLeaf),
335    /// Invalid [`LeafNodeParameters`]. `[CredentialWithKey]` can't be set with new signer.
336    #[error("Invalid LeafNodeParameters. CredentialWithKey can't be set with new signer.")]
337    InvalidLeafNodeParameters,
338    /// Invalid external commit.
339    #[error("Invalid external commit.")]
340    InvalidExternalCommit(#[from] ExternalCommitValidationError),
341    /// See [`ApplyAppDataUpdateError`] for more details.
342    #[cfg(feature = "extensions-draft-08")]
343    #[error(transparent)]
344    ApplyAppDataUpdateError(#[from] ApplyAppDataUpdateError),
345    /// See [`LeafNodeValidationError`] for more details.
346    #[error(transparent)]
347    LeafNodeValidation(#[from] LeafNodeValidationError),
348}
349
350/// Stage commit error
351#[derive(Error, Debug, PartialEq, Clone)]
352pub enum CommitBuilderStageError<StorageError> {
353    /// See [`LibraryError`] for more details.
354    #[error(transparent)]
355    LibraryError(#[from] LibraryError),
356    /// Error interacting with storage.
357    #[error("Error interacting with storage.")]
358    KeyStoreError(StorageError),
359}
360
361/// Stage commit error
362#[derive(Error, Debug, PartialEq, Clone)]
363pub enum ExternalCommitBuilderFinalizeError<StorageError> {
364    /// See [`LibraryError`] for more details.
365    #[error(transparent)]
366    LibraryError(#[from] LibraryError),
367    /// Error interacting with storage.
368    #[error("Error interacting with storage.")]
369    StorageError(StorageError),
370    /// Error merging external commit.
371    #[error("Error merging external commit.")]
372    MergeCommitError(#[from] MergePendingCommitError<StorageError>),
373}
374
375/// Validation error
376#[derive(Error, Debug, PartialEq, Clone)]
377pub enum ValidationError {
378    /// See [`LibraryError`] for more details.
379    #[error(transparent)]
380    LibraryError(#[from] LibraryError),
381    /// Message group ID differs from the group's group ID.
382    #[error("Message group ID differs from the group's group ID.")]
383    WrongGroupId,
384    /// Message epoch differs from the group's epoch.
385    #[error("Message epoch differs from the group's epoch.")]
386    WrongEpoch,
387    /// The PublicMessage is not a Commit despite the sender begin of type [NewMemberCommit](crate::prelude::Sender::NewMemberCommit).
388    #[error("The PublicMessage is not a Commit despite the sender begin of type NewMemberCommit.")]
389    NotACommit,
390    /// The PublicMessage is not an External Add Proposal despite the sender begin of type [NewMemberProposal](crate::prelude::Sender::NewMemberProposal).
391    #[error("The PublicMessage is not an external Add proposal despite the sender begin of type NewMemberProposal.")]
392    NotAnExternalAddProposal,
393    /// The Commit doesn't have a path despite the sender being of type NewMemberCommit.
394    #[error("The Commit doesn't have a path despite the sender being of type NewMemberCommit.")]
395    NoPath,
396    /// The PublicMessage contains an application message but was not encrypted.
397    #[error("The PublicMessage contains an application message but was not encrypted.")]
398    UnencryptedApplicationMessage,
399    /// Sender is not part of the group.
400    #[error("Sender is not part of the group.")]
401    UnknownMember,
402    /// Membership tag is missing.
403    #[error("Membership tag is missing.")]
404    MissingMembershipTag,
405    /// Membership tag is invalid.
406    #[error("Membership tag is invalid.")]
407    InvalidMembershipTag,
408    /// The confirmation tag is missing.
409    #[error("The confirmation tag is missing.")]
410    MissingConfirmationTag,
411    /// Wrong wire format.
412    #[error("Wrong wire format.")]
413    WrongWireFormat,
414    /// Verifying the signature failed.
415    #[error("Verifying the signature failed.")]
416    InvalidSignature,
417    /// An application message was sent from an external sender.
418    #[error("An application message was sent from an external sender.")]
419    NonMemberApplicationMessage,
420    /// Could not decrypt the message
421    #[error(transparent)]
422    UnableToDecrypt(#[from] MessageDecryptionError),
423    /// The message is from an epoch too far in the past.
424    #[error("The message is from an epoch too far in the past.")]
425    NoPastEpochData,
426    /// The provided external sender is not authorized to send external proposals
427    #[error("The provided external sender is not authorized to send external proposals")]
428    UnauthorizedExternalSender,
429    /// The group doesn't contain external senders extension.
430    #[error("The group doesn't contain external senders extension")]
431    NoExternalSendersExtension,
432    /// The KeyPackage could not be validated.
433    #[error(transparent)]
434    KeyPackageVerifyError(#[from] KeyPackageVerifyError),
435    /// The UpdatePath could not be validated.
436    #[error(transparent)]
437    UpdatePathError(#[from] UpdatePathError),
438    /// Invalid LeafNode signature.
439    #[error("Invalid LeafNode signature.")]
440    InvalidLeafNodeSignature,
441    /// Invalid LeafNode source type
442    #[error("Invalid LeafNode source type")]
443    InvalidLeafNodeSourceType,
444    /// Invalid sender type.
445    #[error("Invalid sender type")]
446    InvalidSenderType,
447    /// The Commit includes update proposals from the committer.
448    #[error("The Commit includes update proposals from the committer.")]
449    CommitterIncludedOwnUpdate,
450    /// The ciphersuite in the KeyPackage of the Add proposal does not match the group context.
451    #[error(
452        "The ciphersuite in the KeyPackage of the Add proposal does not match the group context."
453    )]
454    InvalidAddProposalCiphersuite,
455    #[cfg(not(feature = "virtual-clients-draft"))]
456    /// Cannot decrypt own messages because the necessary key has been deleted according to the deletion schedule.
457    #[error("Cannot decrypt own messages.")]
458    CannotDecryptOwnMessage,
459    /// See [`ExternalCommitValidationError`] for more details.
460    #[error(transparent)]
461    ExternalCommitValidation(#[from] ExternalCommitValidationError),
462    /// See [`InvalidExtensionError`]
463    #[error("Invalid extension")]
464    InvalidExtension(#[from] InvalidExtensionError),
465}
466
467/// Proposal validation error
468#[derive(Error, Debug, PartialEq, Clone)]
469pub enum ProposalValidationError {
470    /// See [`LibraryError`] for more details.
471    #[error(transparent)]
472    LibraryError(#[from] LibraryError),
473    /// The sender could not be matched to a member of the group.
474    #[error("The sender could not be matched to a member of the group.")]
475    UnknownMember,
476    /// Duplicate signature key in proposals and group.
477    #[error("Duplicate signature key in proposals and group.")]
478    DuplicateSignatureKey,
479    /// Duplicate encryption key in proposals and group.
480    #[error("Duplicate encryption key in proposals and group.")]
481    DuplicateEncryptionKey,
482    /// Duplicate init key in proposals.
483    #[error("Duplicate init key in proposals.")]
484    DuplicateInitKey,
485    /// The HPKE init and encryption keys are the same.
486    #[error("The HPKE init and encryption keys are the same.")]
487    InitEncryptionKeyCollision,
488    /// Duplicate remove proposals for the same member.
489    #[error("Duplicate remove proposals for the same member.")]
490    DuplicateMemberRemoval,
491    /// The remove proposal referenced a non-existing member.
492    #[error("The remove proposal referenced a non-existing member.")]
493    UnknownMemberRemoval,
494    /// Found an update from a non-member.
495    #[error("Found an update from a non-member.")]
496    UpdateFromNonMember,
497    /// The Commit includes update proposals from the committer.
498    #[error("The Commit includes update proposals from the committer.")]
499    CommitterIncludedOwnUpdate,
500    /// The capabilities of the add proposal are insufficient for this group.
501    #[error("The capabilities of the add proposal are insufficient for this group.")]
502    InsufficientCapabilities,
503    /// The add proposal's ciphersuite or protocol version do not match the ones in the group context.
504    #[error(
505        "The add proposal's ciphersuite or protocol version do not match the ones in the group context."
506    )]
507    InvalidAddProposalCiphersuiteOrVersion,
508    /// See [`PskError`] for more details.
509    #[error(transparent)]
510    Psk(#[from] PskError),
511    /// The proposal type is not supported by all group members.
512    #[error("The proposal type is not supported by all group members.")]
513    UnsupportedProposalType,
514    /// See [`LeafNodeValidationError`] for more details.
515    #[error(transparent)]
516    LeafNodeValidation(#[from] LeafNodeValidationError),
517    /// Regular Commits may not contain ExternalInit proposals, but one was found
518    #[error("Found ExternalInit proposal in regular commit")]
519    ExternalInitProposalInRegularCommit,
520}
521
522/// External Commit validaton error
523#[derive(Error, Debug, PartialEq, Clone)]
524pub enum ExternalCommitValidationError {
525    /// See [`LibraryError`] for more details.
526    #[error(transparent)]
527    LibraryError(#[from] LibraryError),
528    /// No ExternalInit proposal found.
529    #[error("No ExternalInit proposal found.")]
530    NoExternalInitProposals,
531    /// Multiple ExternalInit proposal found.
532    #[error("Multiple ExternalInit proposal found.")]
533    MultipleExternalInitProposals,
534    /// Found inline Add or Update proposals.
535    #[error("Found inline Add or Update proposals.")]
536    InvalidInlineProposals,
537    /// Found multiple inline Remove proposals.
538    #[error("Found multiple inline Remove proposals.")]
539    MultipleRemoveProposals,
540    /// Remove proposal targets the wrong group member.
541    #[error("Remove proposal targets the wrong group member.")]
542    InvalidRemoveProposal,
543    /// External Commit has to contain a path.
544    #[error("External Commit has to contain a path.")]
545    NoPath,
546    /// External commit contains referenced proposal
547    #[error("Found a referenced proposal in an External Commit.")]
548    ReferencedProposal,
549    /// External committer's leaf node does not support all group context extensions.
550    #[error("External committer's leaf node does not support all group context extensions.")]
551    UnsupportedGroupContextExtensions,
552}
553
554/// Create add proposal error
555#[derive(Error, Debug, PartialEq, Clone)]
556pub enum CreateAddProposalError {
557    /// See [`LibraryError`] for more details.
558    #[error(transparent)]
559    LibraryError(#[from] LibraryError),
560    /// See [`LeafNodeValidationError`] for more details.
561    #[error(transparent)]
562    LeafNodeValidation(#[from] LeafNodeValidationError),
563}
564
565// === Crate errors ===
566
567/// Proposal queue error
568#[derive(Error, Debug, PartialEq, Clone)]
569pub(crate) enum ProposalQueueError {
570    /// See [`LibraryError`] for more details.
571    #[error(transparent)]
572    LibraryError(#[from] LibraryError),
573    /// Not all proposals in the Commit were found locally.
574    #[error("Not all proposals in the Commit were found locally.")]
575    ProposalNotFound,
576    /// Update proposal from external sender.
577    #[error("Update proposal from external sender.")]
578    UpdateFromExternalSender,
579    /// SelfRemove proposal from a non-Member.
580    #[error("SelfRemove proposal from a non-Member.")]
581    SelfRemoveFromNonMember,
582}
583
584/// Errors that can arise when creating a [`ProposalQueue`] from committed
585/// proposals.
586#[derive(Error, Debug, PartialEq, Clone)]
587pub(crate) enum FromCommittedProposalsError {
588    /// See [`LibraryError`] for more details.
589    #[error(transparent)]
590    LibraryError(#[from] LibraryError),
591    /// Not all proposals in the Commit were found locally.
592    #[error("Not all proposals in the Commit were found locally.")]
593    ProposalNotFound,
594    /// The sender of a Commit tried to remove themselves.
595    #[error("The sender of a Commit tried to remove themselves.")]
596    SelfRemoval,
597    /// Commit contains two PSK proposals with the same PSK ID.
598    #[error("Commit contains two PSK proposals the PSK ID {0:?}.")]
599    DuplicatePskId(PreSharedKeyId),
600}
601
602/// Create group context ext proposal error
603#[derive(Error, Debug, PartialEq, Clone)]
604pub enum CreateGroupContextExtProposalError<StorageError> {
605    /// See [`LibraryError`] for more details.
606    #[error(transparent)]
607    LibraryError(#[from] LibraryError),
608    /// See [`KeyPackageExtensionSupportError`] for more details.
609    #[error(transparent)]
610    KeyPackageExtensionSupport(#[from] KeyPackageExtensionSupportError),
611    /// See [`ExtensionError`] for more details.
612    #[error(transparent)]
613    Extension(#[from] ExtensionError),
614    /// See [`LeafNodeValidationError`] for more details.
615    #[error(transparent)]
616    LeafNodeValidation(#[from] LeafNodeValidationError),
617    /// See [`MlsGroupStateError`] for more details.
618    #[error(transparent)]
619    MlsGroupStateError(#[from] MlsGroupStateError),
620    /// See [`CreateCommitError`] for more details.
621    #[error(transparent)]
622    CreateCommitError(#[from] CreateCommitError),
623    /// See [`CommitBuilderStageError`] for more details.
624    #[error(transparent)]
625    CommitBuilderStageError(#[from] CommitBuilderStageError<StorageError>),
626    /// Error writing updated group to storage.
627    #[error("Error writing updated group data to storage.")]
628    StorageError(StorageError),
629    /// Error validating the extensions
630    #[error(transparent)]
631    InvalidExtensionError(#[from] InvalidExtensionError),
632}
633
634/// Error merging a commit.
635#[derive(Error, Debug, PartialEq, Clone)]
636pub enum MergeCommitError<StorageError> {
637    /// See [`LibraryError`] for more details.
638    #[error(transparent)]
639    LibraryError(#[from] LibraryError),
640    /// Error writing updated group to storage.
641    #[error("Error writing updated group data to storage.")]
642    StorageError(StorageError),
643}
644
645#[cfg(feature = "extensions-draft-08")]
646/// Error validating an AppDataUpdate proposal.
647#[derive(Error, Debug, PartialEq, Clone)]
648pub enum AppDataUpdateValidationError {
649    /// [`AppDataUpdateProposal`](crate::messages::proposals::AppDataUpdateProposal)s
650    /// occur before
651    /// [`GroupContextExtensionsProposal`](crate::messages::proposals::GroupContextExtensionProposal)s.
652    #[error("AppDataUpdate proposals occur before GroupContextExtensions proposals.")]
653    IncorrectOrder,
654    /// Attempted to update the [`AppDataDictionary`](crate::extensions::AppDataDictionary)
655    /// in the
656    /// [`GroupContextExtensionsProposal`](crate::messages::proposals::GroupContextExtensionProposal) directly.
657    #[error("Attempted to update the AppDataDictionary in the GroupContextExtensions proposal directly.")]
658    CannotUpdateDictionaryDirectly,
659    /// More than one [`AppDataUpdate]` proposal per [`ComponentId`] had a Remove operation.
660    ///
661    /// [`ComponentId`]: crate::component::ComponentId
662    #[error("More than one AppDataUpdate proposal per ComponentId had a Remove operation.")]
663    MoreThanOneRemovePerComponentId,
664    /// Proposals for a [`ComponentId`] had both Remove and Update operations.
665    ///
666    /// [`ComponentId`]: crate::component::ComponentId
667    #[error("Proposals for a ComponentId had both Remove and Update operations.")]
668    CombinedRemoveAndUpdateOperations,
669    /// Proposals for a [`ComponentId`] had a Remove for a nonexistent component.
670    ///
671    /// [`ComponentId`]: crate::component::ComponentId
672    #[error("Proposals for a ComponentId had a Remove for a nonexistent component.")]
673    CannotRemoveNonexistentComponent,
674}
675
676/// Error validation a GroupContextExtensions proposal.
677#[derive(Error, Debug, PartialEq, Clone)]
678pub enum GroupContextExtensionsProposalValidationError {
679    /// Commit has more than one GroupContextExtensions proposal.
680    #[error("Commit has more than one GroupContextExtensions proposal.")]
681    TooManyGCEProposals,
682
683    /// See [`LibraryError`] for more details.
684    #[error(transparent)]
685    LibraryError(#[from] LibraryError),
686
687    /// The new extension types in required capabilties contails extensions that are not supported by all group members.
688    #[error(
689        "The new required capabilties contain extension types that are not supported by all group members."
690    )]
691    ExtensionNotSupportedByAllMembers,
692    /// Proposal changes the immutable metadata extension, which is not allowed.
693    #[error("Proposal changes the immutable metadata extension, which is not allowed.")]
694    ChangedImmutableMetadata,
695
696    /// The new extension types in required capabilties contails extensions that are not supported by all group members.
697    #[error(
698        "The new required capabilties contain extension types that are not supported by all group members."
699    )]
700    RequiredExtensionNotSupportedByAllMembers,
701
702    /// An extension in the group context extensions is not listed in the required capabilties'
703    /// extension types.
704    #[error(
705        "An extension in the group context extensions is not listed in the required capabilties' extension types."
706    )]
707    ExtensionNotInRequiredCapabilities,
708
709    /// An extension with a type that is not valid in the group context
710    #[error("Expected valid `Extension` for `GroupContextExtension`, got `{wrong:?}`")]
711    InvalidExtensionTypeError {
712        /// found invalid type
713        wrong: ExtensionType,
714    },
715}