Skip to main content

ruma_common/api/error/
kind.rs

1#[cfg(feature = "unstable-msc4363")]
2use std::collections::BTreeSet;
3use std::str::FromStr;
4
5use as_variant::as_variant;
6use ruma_common::{
7    RoomVersionId,
8    api::error::{HeaderDeserializationError, HeaderSerializationError},
9    http_headers::{http_date_to_system_time, system_time_to_http_date},
10    serde::{JsonObject, StringEnum},
11};
12use web_time::{Duration, SystemTime};
13
14#[cfg(feature = "unstable-msc4406")]
15use crate::OwnedUserId;
16use crate::PrivOwnedStr;
17#[cfg(feature = "unstable-msc4363")]
18use crate::{OwnedAcr, api::OAuthClientScope};
19
20/// An enum for the error kind.
21///
22/// Items may contain additional information.
23#[derive(Clone, Debug, PartialEq, Eq)]
24#[non_exhaustive]
25// Please keep the variants sorted alphabetically.
26pub enum ErrorKind {
27    /// `M_APPSERVICE_LOGIN_UNSUPPORTED`
28    ///
29    /// An application service used the [`m.login.application_service`] type an endpoint from the
30    /// [legacy authentication API] in a way that is not supported by the homeserver, because the
31    /// server only supports the [OAuth 2.0 API].
32    ///
33    /// [`m.login.application_service`]: https://spec.matrix.org/v1.19/application-service-api/#server-admin-style-permissions
34    /// [legacy authentication API]: https://spec.matrix.org/v1.19/client-server-api/#legacy-api
35    /// [OAuth 2.0 API]: https://spec.matrix.org/v1.19/client-server-api/#oauth-20-api
36    AppserviceLoginUnsupported,
37
38    /// `M_BAD_ALIAS`
39    ///
40    /// One or more [room aliases] within the `m.room.canonical_alias` event do not point to the
41    /// room ID for which the state event is to be sent to.
42    ///
43    /// [room aliases]: https://spec.matrix.org/v1.19/client-server-api/#room-aliases
44    BadAlias,
45
46    /// `M_BAD_JSON`
47    ///
48    /// The request contained valid JSON, but it was malformed in some way, e.g. missing required
49    /// keys, invalid values for keys.
50    BadJson,
51
52    /// `M_BAD_STATE`
53    ///
54    /// The state change requested cannot be performed, such as attempting to unban a user who is
55    /// not banned.
56    BadState,
57
58    /// `M_BAD_STATUS`
59    ///
60    /// The application service returned a bad status.
61    BadStatus(BadStatusErrorData),
62
63    /// `M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
64    ///
65    /// The user is unable to reject an invite to join the [server notices] room.
66    ///
67    /// [server notices]: https://spec.matrix.org/v1.19/client-server-api/#server-notices
68    CannotLeaveServerNoticeRoom,
69
70    /// `M_CANNOT_OVERWRITE_MEDIA`
71    ///
72    /// The `PUT /_matrix/media/*/upload/{serverName}/{mediaId}` endpoint was called with a media ID
73    /// that already has content.
74    CannotOverwriteMedia,
75
76    /// `M_CAPTCHA_INVALID`
77    ///
78    /// The Captcha provided did not match what was expected.
79    CaptchaInvalid,
80
81    /// `M_CAPTCHA_NEEDED`
82    ///
83    /// A Captcha is required to complete the request.
84    CaptchaNeeded,
85
86    /// `M_CONCURRENT_WRITE`
87    ///
88    /// The sequence token provided when updating a rendezvous session
89    /// does not match the current sequence token.
90    #[cfg(feature = "unstable-msc4388")]
91    ConcurrentWrite,
92
93    /// `M_CONFLICTING_UNSUBSCRIPTION`
94    ///
95    /// Part of [MSC4306]: an automatic thread subscription has been skipped by the server, because
96    /// the user unsubsubscribed after the indicated subscribed-to event.
97    ///
98    /// [MSC4306]: https://github.com/matrix-org/matrix-spec-proposals/pull/4306
99    #[cfg(feature = "unstable-msc4306")]
100    ConflictingUnsubscription,
101
102    /// `M_CONNECTION_FAILED`
103    ///
104    /// The connection to the application service failed.
105    ConnectionFailed,
106
107    /// `M_CONNECTION_TIMEOUT`
108    ///
109    /// The connection to the application service timed out.
110    ConnectionTimeout,
111
112    /// `M_DUPLICATE_ANNOTATION`
113    ///
114    /// The request is an attempt to send a [duplicate annotation].
115    ///
116    /// [duplicate annotation]: https://spec.matrix.org/v1.19/client-server-api/#avoiding-duplicate-annotations
117    DuplicateAnnotation,
118
119    /// `M_EXCLUSIVE`
120    ///
121    /// The resource being requested is reserved by an application service, or the application
122    /// service making the request has not created the resource.
123    Exclusive,
124
125    /// `M_FORBIDDEN`
126    ///
127    /// Forbidden access, e.g. joining a room without permission, failed login.
128    Forbidden,
129
130    /// `M_GUEST_ACCESS_FORBIDDEN`
131    ///
132    /// The room or resource does not permit [guests] to access it.
133    ///
134    /// [guests]: https://spec.matrix.org/v1.19/client-server-api/#guest-access
135    GuestAccessForbidden,
136
137    /// `M_INCOMPATIBLE_ROOM_VERSION`
138    ///
139    /// The client attempted to join a room that has a version the server does not support.
140    IncompatibleRoomVersion(IncompatibleRoomVersionErrorData),
141
142    /// `M_INSUFFICIENT_USER_AUTHENTICATION`
143    ///
144    /// The client needs to reauthenticate with the OAuth authorization server to use
145    /// this endpoint. ([MSC4363])
146    ///
147    /// [MSC4363]: https://github.com/matrix-org/matrix-spec-proposals/pull/4363
148    #[cfg(feature = "unstable-msc4363")]
149    InsufficientUserAuthentication(Box<InsufficientUserAuthenticationErrorData>),
150
151    /// `M_INVALID_PARAM`
152    ///
153    /// A parameter that was specified has the wrong value. For example, the server expected an
154    /// integer and instead received a string.
155    InvalidParam,
156
157    /// `M_INVALID_ROOM_STATE`
158    ///
159    /// The initial state implied by the parameters to the `POST /_matrix/client/*/createRoom`
160    /// request is invalid, e.g. the user's `power_level` is set below that necessary to set the
161    /// room name.
162    InvalidRoomState,
163
164    /// `M_INVALID_USERNAME`
165    ///
166    /// The desired user name is not valid.
167    InvalidUsername,
168
169    /// `M_INVITE_BLOCKED`
170    ///
171    /// The invite was interdicted by moderation tools or configured access controls without having
172    /// been witnessed by the invitee.
173    InviteBlocked,
174
175    /// `M_KEY_TOO_LARGE`
176    ///
177    /// The [profile] key in the request exceeds the maximum allowed length of 255 bytes.
178    ///
179    /// [profile]: https://spec.matrix.org/v1.19/client-server-api/#profiles
180    KeyTooLarge,
181
182    /// `M_LIMIT_EXCEEDED`
183    ///
184    /// The request has been refused due to [rate limiting]: too many requests have been sent in a
185    /// short period of time.
186    ///
187    /// [rate limiting]: https://spec.matrix.org/v1.19/client-server-api/#rate-limiting
188    LimitExceeded(LimitExceededErrorData),
189
190    /// `M_MISSING_PARAM`
191    ///
192    /// A required parameter was missing from the request.
193    MissingParam,
194
195    /// `M_MISSING_TOKEN`
196    ///
197    /// No [access token] was specified for the request, but one is required.
198    ///
199    /// [access token]: https://spec.matrix.org/v1.19/client-server-api/#client-authentication
200    MissingToken,
201
202    /// `M_NOT_FOUND`
203    ///
204    /// No resource was found for this request.
205    NotFound,
206
207    /// `M_NOT_IN_THREAD`
208    ///
209    /// Part of [MSC4306]: an automatic thread subscription was set to an event ID that isn't part
210    /// of the subscribed-to thread.
211    ///
212    /// [MSC4306]: https://github.com/matrix-org/matrix-spec-proposals/pull/4306
213    #[cfg(feature = "unstable-msc4306")]
214    NotInThread,
215
216    /// `M_NOT_JSON`
217    ///
218    /// The request did not contain valid JSON.
219    NotJson,
220
221    /// `M_NOT_YET_UPLOADED`
222    ///
223    /// An `mxc:` URI generated with the `POST /_matrix/media/*/create` endpoint was used and the
224    /// content is not yet available.
225    NotYetUploaded,
226
227    /// `M_PROFILE_TOO_LARGE`
228    ///
229    /// Storing the value in the request would make the [profile] exceed its maximum allowed size
230    /// of 64 KiB.
231    ///
232    /// [profile]: https://spec.matrix.org/v1.19/client-server-api/#profiles
233    ProfileTooLarge,
234
235    /// `M_RESOURCE_LIMIT_EXCEEDED`
236    ///
237    /// The request cannot be completed because the homeserver has reached a resource limit imposed
238    /// on it. For example, a homeserver held in a shared hosting environment may reach a resource
239    /// limit if it starts using too much memory or disk space.
240    ResourceLimitExceeded(ResourceLimitExceededErrorData),
241
242    /// `M_ROOM_IN_USE`
243    ///
244    /// The [room alias] specified in the `POST /_matrix/client/*/createRoom` request is already
245    /// taken.
246    ///
247    /// [room alias]: https://spec.matrix.org/v1.19/client-server-api/#room-aliases
248    RoomInUse,
249
250    /// `M_SENDER_IGNORED`
251    ///
252    /// The sender of the requested event is ignored by the requesting user. ([MSC])
253    ///
254    /// [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/4406
255    #[cfg(feature = "unstable-msc4406")]
256    SenderIgnored(SenderIgnoredErrorData),
257
258    /// `M_SERVER_NOT_TRUSTED`
259    ///
260    /// The client's request used a third-party server, e.g. identity server, that this server does
261    /// not trust.
262    ServerNotTrusted,
263
264    /// `M_THREEPID_AUTH_FAILED`
265    ///
266    /// Authentication could not be performed on the [third-party identifier].
267    ///
268    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
269    ThreepidAuthFailed,
270
271    /// `M_THREEPID_DENIED`
272    ///
273    /// The server does not permit this [third-party identifier]. This may happen if the server
274    /// only permits, for example, email addresses from a particular domain.
275    ///
276    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
277    ThreepidDenied,
278
279    /// `M_THREEPID_IN_USE`
280    ///
281    /// The [third-party identifier] is already in use by another user.
282    ///
283    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
284    ThreepidInUse,
285
286    /// `M_THREEPID_MEDIUM_NOT_SUPPORTED`
287    ///
288    /// The homeserver does not support adding a [third-party identifier] of the given medium.
289    ///
290    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
291    ThreepidMediumNotSupported,
292
293    /// `M_THREEPID_NOT_FOUND`
294    ///
295    /// No account matching the given [third-party identifier] could be found.
296    ///
297    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
298    ThreepidNotFound,
299
300    /// `M_TOKEN_INCORRECT`
301    ///
302    /// The token that the user entered to validate the session is incorrect.
303    TokenIncorrect,
304
305    /// `M_TOO_LARGE`
306    ///
307    /// The request or entity was too large.
308    TooLarge,
309
310    /// `M_UNABLE_TO_AUTHORISE_JOIN`
311    ///
312    /// The room is [restricted] and none of the conditions can be validated by the homeserver.
313    /// This can happen if the homeserver does not know about any of the rooms listed as
314    /// conditions, for example.
315    ///
316    /// [restricted]: https://spec.matrix.org/v1.19/client-server-api/#restricted-rooms
317    UnableToAuthorizeJoin,
318
319    /// `M_UNABLE_TO_GRANT_JOIN`
320    ///
321    /// A different server should be attempted for the join. This is typically because the resident
322    /// server can see that the joining user satisfies one or more conditions, such as in the case
323    /// of [restricted rooms], but the resident server would be unable to meet the authorization
324    /// rules.
325    ///
326    /// [restricted rooms]: https://spec.matrix.org/v1.19/client-server-api/#restricted-rooms
327    UnableToGrantJoin,
328
329    /// `M_UNACTIONABLE`
330    ///
331    /// The server does not want to handle the [federated report].
332    ///
333    /// [federated report]: https://github.com/matrix-org/matrix-spec-proposals/pull/3843
334    #[cfg(feature = "unstable-msc3843")]
335    Unactionable,
336
337    /// `M_UNAUTHORIZED`
338    ///
339    /// The request was not correctly authorized. Usually due to login failures.
340    Unauthorized,
341
342    /// `M_UNKNOWN`
343    ///
344    /// An unknown error has occurred.
345    Unknown,
346
347    /// `M_UNKNOWN_DEVICE`
348    ///
349    /// The device ID supplied by the application service does not belong to the user ID during
350    /// [identity assertion].
351    ///
352    /// [identity assertion]: https://spec.matrix.org/v1.19/application-service-api/#identity-assertion
353    UnknownDevice,
354
355    /// `M_UNKNOWN_POS`
356    ///
357    /// The sliding sync ([MSC4186]) connection was expired by the server.
358    ///
359    /// [MSC4186]: https://github.com/matrix-org/matrix-spec-proposals/pull/4186
360    #[cfg(feature = "unstable-msc4186")]
361    UnknownPos,
362
363    /// `M_UNKNOWN_TOKEN`
364    ///
365    /// The [access or refresh token] specified was not recognized.
366    ///
367    /// [access or refresh token]: https://spec.matrix.org/v1.19/client-server-api/#client-authentication
368    UnknownToken(UnknownTokenErrorData),
369
370    /// `M_UNRECOGNIZED`
371    ///
372    /// The server did not understand the request.
373    ///
374    /// This is expected to be returned with a 404 HTTP status code if the endpoint is not
375    /// implemented or a 405 HTTP status code if the endpoint is implemented, but the incorrect
376    /// HTTP method is used.
377    Unrecognized,
378
379    /// `M_UNSUPPORTED_ROOM_VERSION`
380    ///
381    /// The request to `POST /_matrix/client/*/createRoom` used a room version that the server does
382    /// not support.
383    UnsupportedRoomVersion,
384
385    /// `M_URL_NOT_SET`
386    ///
387    /// The application service doesn't have a URL configured.
388    UrlNotSet,
389
390    /// `M_USER_DEACTIVATED`
391    ///
392    /// The user ID associated with the request has been deactivated.
393    UserDeactivated,
394
395    /// `M_USER_IN_USE`
396    ///
397    /// The desired user ID is already taken.
398    UserInUse,
399
400    /// `M_USER_LIMIT_EXCEEDED`
401    ///
402    /// The request cannot be completed because the user has exceeded (or the request would cause
403    /// them to exceed) a limit associated with their account. For example, a user may have reached
404    /// their allocated storage quota, reached a maximum number of allowed rooms, devices, or other
405    /// account-scoped resources, or exceeded usage limits for specific features.
406    UserLimitExceeded(UserLimitExceededErrorData),
407
408    /// `M_USER_LOCKED`
409    ///
410    /// The account has been [locked] and cannot be used at this time.
411    ///
412    /// [locked]: https://spec.matrix.org/v1.19/client-server-api/#account-locking
413    UserLocked,
414
415    /// `M_USER_SUSPENDED`
416    ///
417    /// The account has been [suspended] and can only be used for limited actions at this time.
418    ///
419    /// [suspended]: https://spec.matrix.org/v1.19/client-server-api/#account-suspension
420    UserSuspended,
421
422    /// `M_WEAK_PASSWORD`
423    ///
424    /// The password was [rejected] by the server for being too weak.
425    ///
426    /// [rejected]: https://spec.matrix.org/v1.19/client-server-api/#password-management
427    WeakPassword,
428
429    /// `M_WRONG_ROOM_KEYS_VERSION`
430    ///
431    /// The version of the [room keys backup] provided in the request does not match the current
432    /// backup version.
433    ///
434    /// [room keys backup]: https://spec.matrix.org/v1.19/client-server-api/#server-side-key-backups
435    WrongRoomKeysVersion(WrongRoomKeysVersionErrorData),
436
437    #[doc(hidden)]
438    _Custom(Box<CustomErrorKind>),
439}
440
441impl ErrorKind {
442    /// Get the [`ErrorCode`] for this `ErrorKind`.
443    pub fn errcode(&self) -> ErrorCode {
444        match self {
445            ErrorKind::AppserviceLoginUnsupported => ErrorCode::AppserviceLoginUnsupported,
446            ErrorKind::BadAlias => ErrorCode::BadAlias,
447            ErrorKind::BadJson => ErrorCode::BadJson,
448            ErrorKind::BadState => ErrorCode::BadState,
449            ErrorKind::BadStatus(_) => ErrorCode::BadStatus,
450            ErrorKind::CannotLeaveServerNoticeRoom => ErrorCode::CannotLeaveServerNoticeRoom,
451            ErrorKind::CannotOverwriteMedia => ErrorCode::CannotOverwriteMedia,
452            ErrorKind::CaptchaInvalid => ErrorCode::CaptchaInvalid,
453            ErrorKind::CaptchaNeeded => ErrorCode::CaptchaNeeded,
454            #[cfg(feature = "unstable-msc4388")]
455            ErrorKind::ConcurrentWrite => ErrorCode::ConcurrentWrite,
456            #[cfg(feature = "unstable-msc4306")]
457            ErrorKind::ConflictingUnsubscription => ErrorCode::ConflictingUnsubscription,
458            ErrorKind::ConnectionFailed => ErrorCode::ConnectionFailed,
459            ErrorKind::ConnectionTimeout => ErrorCode::ConnectionTimeout,
460            ErrorKind::DuplicateAnnotation => ErrorCode::DuplicateAnnotation,
461            ErrorKind::Exclusive => ErrorCode::Exclusive,
462            ErrorKind::Forbidden => ErrorCode::Forbidden,
463            ErrorKind::GuestAccessForbidden => ErrorCode::GuestAccessForbidden,
464            ErrorKind::IncompatibleRoomVersion(_) => ErrorCode::IncompatibleRoomVersion,
465            #[cfg(feature = "unstable-msc4363")]
466            ErrorKind::InsufficientUserAuthentication(_) => {
467                ErrorCode::InsufficientUserAuthentication
468            }
469            ErrorKind::InvalidParam => ErrorCode::InvalidParam,
470            ErrorKind::InvalidRoomState => ErrorCode::InvalidRoomState,
471            ErrorKind::InvalidUsername => ErrorCode::InvalidUsername,
472            ErrorKind::InviteBlocked => ErrorCode::InviteBlocked,
473            ErrorKind::KeyTooLarge => ErrorCode::KeyTooLarge,
474            ErrorKind::LimitExceeded(_) => ErrorCode::LimitExceeded,
475            ErrorKind::MissingParam => ErrorCode::MissingParam,
476            ErrorKind::MissingToken => ErrorCode::MissingToken,
477            ErrorKind::NotFound => ErrorCode::NotFound,
478            #[cfg(feature = "unstable-msc4306")]
479            ErrorKind::NotInThread => ErrorCode::NotInThread,
480            ErrorKind::NotJson => ErrorCode::NotJson,
481            ErrorKind::NotYetUploaded => ErrorCode::NotYetUploaded,
482            ErrorKind::ProfileTooLarge => ErrorCode::ProfileTooLarge,
483            ErrorKind::ResourceLimitExceeded(_) => ErrorCode::ResourceLimitExceeded,
484            ErrorKind::RoomInUse => ErrorCode::RoomInUse,
485            #[cfg(feature = "unstable-msc4406")]
486            ErrorKind::SenderIgnored(_) => ErrorCode::SenderIgnored,
487            ErrorKind::ServerNotTrusted => ErrorCode::ServerNotTrusted,
488            ErrorKind::ThreepidAuthFailed => ErrorCode::ThreepidAuthFailed,
489            ErrorKind::ThreepidDenied => ErrorCode::ThreepidDenied,
490            ErrorKind::ThreepidInUse => ErrorCode::ThreepidInUse,
491            ErrorKind::ThreepidMediumNotSupported => ErrorCode::ThreepidMediumNotSupported,
492            ErrorKind::ThreepidNotFound => ErrorCode::ThreepidNotFound,
493            ErrorKind::TokenIncorrect => ErrorCode::TokenIncorrect,
494            ErrorKind::TooLarge => ErrorCode::TooLarge,
495            ErrorKind::UnableToAuthorizeJoin => ErrorCode::UnableToAuthorizeJoin,
496            ErrorKind::UnableToGrantJoin => ErrorCode::UnableToGrantJoin,
497            #[cfg(feature = "unstable-msc3843")]
498            ErrorKind::Unactionable => ErrorCode::Unactionable,
499            ErrorKind::Unauthorized => ErrorCode::Unauthorized,
500            ErrorKind::Unknown => ErrorCode::Unknown,
501            ErrorKind::UnknownDevice => ErrorCode::UnknownDevice,
502            #[cfg(feature = "unstable-msc4186")]
503            ErrorKind::UnknownPos => ErrorCode::UnknownPos,
504            ErrorKind::UnknownToken(_) => ErrorCode::UnknownToken,
505            ErrorKind::Unrecognized => ErrorCode::Unrecognized,
506            ErrorKind::UnsupportedRoomVersion => ErrorCode::UnsupportedRoomVersion,
507            ErrorKind::UrlNotSet => ErrorCode::UrlNotSet,
508            ErrorKind::UserDeactivated => ErrorCode::UserDeactivated,
509            ErrorKind::UserInUse => ErrorCode::UserInUse,
510            ErrorKind::UserLimitExceeded(_) => ErrorCode::UserLimitExceeded,
511            ErrorKind::UserLocked => ErrorCode::UserLocked,
512            ErrorKind::UserSuspended => ErrorCode::UserSuspended,
513            ErrorKind::WeakPassword => ErrorCode::WeakPassword,
514            ErrorKind::WrongRoomKeysVersion(_) => ErrorCode::WrongRoomKeysVersion,
515            ErrorKind::_Custom(kind) => kind.errcode.as_str().into(),
516        }
517    }
518
519    /// Get the JSON data for this `ErrorKind`, if it uses a custom error code.
520    pub fn custom_json_data(&self) -> Option<&JsonObject> {
521        as_variant!(self, Self::_Custom(error_kind) => &error_kind.data)
522    }
523}
524
525/// Data for the `M_BAD_STATUS` [`ErrorKind`].
526#[derive(Clone, Debug, Default, PartialEq, Eq)]
527#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
528pub struct BadStatusErrorData {
529    /// The HTTP status code of the response.
530    pub status: Option<http::StatusCode>,
531
532    /// The body of the response.
533    pub body: Option<String>,
534}
535
536impl BadStatusErrorData {
537    /// Construct a new empty `BadStatusErrorData`.
538    pub fn new() -> Self {
539        Self::default()
540    }
541}
542
543/// Data for the `M_INCOMPATIBLE_ROOM_VERSION` [`ErrorKind`].
544#[derive(Clone, Debug, PartialEq, Eq)]
545#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
546pub struct IncompatibleRoomVersionErrorData {
547    /// The room's version.
548    pub room_version: RoomVersionId,
549}
550
551impl IncompatibleRoomVersionErrorData {
552    /// Construct a new `IncompatibleRoomVersionErrorData` with the given room version.
553    pub fn new(room_version: RoomVersionId) -> Self {
554        Self { room_version }
555    }
556}
557
558/// Data for the `M_INSUFFICIENT_USER_AUTHENTICATION` [`ErrorKind`].
559#[derive(Clone, Debug, Default, PartialEq, Eq)]
560#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
561#[cfg(feature = "unstable-msc4363")]
562pub struct InsufficientUserAuthenticationErrorData {
563    /// The ACR values to supply to the auth server.
564    pub acr_values: Vec<OwnedAcr>,
565
566    /// The maximum number of seconds since the last authentication
567    /// until authentication must be performed again.
568    pub max_age: Option<Duration>,
569
570    /// The scopes required to access the resource.
571    pub scope: BTreeSet<OAuthClientScope>,
572}
573
574#[cfg(feature = "unstable-msc4363")]
575impl InsufficientUserAuthenticationErrorData {
576    /// Construct a new empty `InsufficientUserAuthenticationErrorData`.
577    pub fn new() -> Self {
578        Self::default()
579    }
580}
581
582/// Data for the `M_LIMIT_EXCEEDED` [`ErrorKind`].
583#[derive(Clone, Debug, Default, PartialEq, Eq)]
584#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
585pub struct LimitExceededErrorData {
586    /// How long a client should wait before they can try again.
587    pub retry_after: Option<RetryAfter>,
588}
589
590impl LimitExceededErrorData {
591    /// Construct a new empty `LimitExceededErrorData`.
592    pub fn new() -> Self {
593        Self::default()
594    }
595}
596
597/// How long a client should wait before it tries again.
598#[derive(Debug, Clone, Copy, PartialEq, Eq)]
599#[allow(clippy::exhaustive_enums)]
600pub enum RetryAfter {
601    /// The client should wait for the given duration.
602    ///
603    /// This variant should be preferred for backwards compatibility, as it will also populate the
604    /// `retry_after_ms` field in the body of the response.
605    Delay(Duration),
606    /// The client should wait for the given date and time.
607    DateTime(SystemTime),
608}
609
610impl TryFrom<&http::HeaderValue> for RetryAfter {
611    type Error = HeaderDeserializationError;
612
613    fn try_from(value: &http::HeaderValue) -> Result<Self, Self::Error> {
614        if value.as_bytes().iter().all(|b| b.is_ascii_digit()) {
615            // It should be a duration.
616            Ok(Self::Delay(Duration::from_secs(u64::from_str(value.to_str()?)?)))
617        } else {
618            // It should be a date.
619            Ok(Self::DateTime(http_date_to_system_time(value)?))
620        }
621    }
622}
623
624impl TryFrom<&RetryAfter> for http::HeaderValue {
625    type Error = HeaderSerializationError;
626
627    fn try_from(value: &RetryAfter) -> Result<Self, Self::Error> {
628        match value {
629            RetryAfter::Delay(duration) => Ok(duration.as_secs().into()),
630            RetryAfter::DateTime(time) => system_time_to_http_date(time),
631        }
632    }
633}
634
635/// Data for the `M_RESOURCE_LIMIT_EXCEEDED` [`ErrorKind`].
636#[derive(Clone, Debug, PartialEq, Eq)]
637#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
638pub struct ResourceLimitExceededErrorData {
639    /// A URI giving a contact method for the server administrator.
640    pub admin_contact: String,
641}
642
643impl ResourceLimitExceededErrorData {
644    /// Construct a new `ResourceLimitExceededErrorData` with the given admin contact URI.
645    pub fn new(admin_contact: String) -> Self {
646        Self { admin_contact }
647    }
648}
649
650/// Data for the `M_SENDER_IGNORED` [`ErrorKind`].
651#[cfg(feature = "unstable-msc4406")]
652#[derive(Clone, Debug, Default, PartialEq, Eq)]
653#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
654pub struct SenderIgnoredErrorData {
655    /// The user who sent the ignored event.
656    pub sender: Option<OwnedUserId>,
657}
658
659#[cfg(feature = "unstable-msc4406")]
660impl SenderIgnoredErrorData {
661    /// Construct a new empty `SenderIgnoredErrorData`.
662    pub fn new() -> Self {
663        Self::default()
664    }
665
666    /// Construct a new `SenderIgnoredErrorData` with the given sender user.
667    pub fn with_sender(sender: OwnedUserId) -> Self {
668        Self { sender: Some(sender) }
669    }
670}
671
672/// Data for the `M_UNKNOWN_TOKEN` [`ErrorKind`].
673#[derive(Clone, Debug, Default, PartialEq, Eq)]
674#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
675pub struct UnknownTokenErrorData {
676    /// If this is `true`, the client is in a "[soft logout]" state, i.e. the server requires
677    /// re-authentication but the session is not invalidated. The client can acquire a new
678    /// access token by specifying the device ID it is already using to the login API.
679    ///
680    /// [soft logout]: https://spec.matrix.org/v1.19/client-server-api/#soft-logout
681    pub soft_logout: bool,
682}
683
684impl UnknownTokenErrorData {
685    /// Construct a new `UnknownTokenErrorData` with `soft_logout` set to `false`.
686    pub fn new() -> Self {
687        Self::default()
688    }
689}
690
691/// Data for the `M_USER_LIMIT_EXCEEDED` [`ErrorKind`].
692#[derive(Clone, Debug, PartialEq, Eq)]
693#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
694pub struct UserLimitExceededErrorData {
695    /// A URI that the client can present to the user to provide more context on the encountered
696    /// limit and, if applicable, guidance on how to increase the limit.
697    ///
698    /// The homeserver MAY return different values depending on the type of limit reached.
699    pub info_uri: String,
700
701    /// Whether the specific limit encountered can be increased.
702    ///
703    /// If `true`, it indicates that the specific limit encountered can be increased, for example
704    /// by upgrading the user’s account tier. If `false`, the limit is a hard limit that cannot be
705    /// increased.
706    ///
707    /// Defaults to `false`.
708    pub can_upgrade: bool,
709}
710
711impl UserLimitExceededErrorData {
712    /// Construct a new `UserLimitExceededErrorData` with the given URI.
713    pub fn new(info_uri: String) -> Self {
714        Self { info_uri, can_upgrade: false }
715    }
716}
717
718/// Data for the `M_WRONG_ROOM_KEYS_VERSION` [`ErrorKind`].
719#[derive(Clone, Debug, PartialEq, Eq)]
720#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
721pub struct WrongRoomKeysVersionErrorData {
722    /// The currently active backup version.
723    pub current_version: String,
724}
725
726impl WrongRoomKeysVersionErrorData {
727    /// Construct a new `WrongRoomKeysVersionErrorData` with the given current active backup
728    /// version.
729    pub fn new(current_version: String) -> Self {
730        Self { current_version }
731    }
732}
733
734/// A custom error kind.
735#[doc(hidden)]
736#[derive(Clone, Debug, PartialEq, Eq)]
737pub struct CustomErrorKind {
738    /// The error code.
739    pub(super) errcode: String,
740
741    /// The data for the error.
742    pub(super) data: JsonObject,
743}
744
745/// The possible [error codes] defined in the Matrix spec.
746///
747/// [error codes]: https://spec.matrix.org/v1.19/client-server-api/#standard-error-response
748#[derive(Clone, StringEnum)]
749#[non_exhaustive]
750#[ruma_enum(rename_all(prefix = "M_", rule = "SCREAMING_SNAKE_CASE"))]
751// Please keep the variants sorted alphabetically.
752pub enum ErrorCode {
753    /// `M_APPSERVICE_LOGIN_UNSUPPORTED`
754    ///
755    /// An application service used the [`m.login.application_service`] type an endpoint from the
756    /// [legacy authentication API] in a way that is not supported by the homeserver, because the
757    /// server only supports the [OAuth 2.0 API].
758    ///
759    /// [`m.login.application_service`]: https://spec.matrix.org/v1.19/application-service-api/#server-admin-style-permissions
760    /// [legacy authentication API]: https://spec.matrix.org/v1.19/client-server-api/#legacy-api
761    /// [OAuth 2.0 API]: https://spec.matrix.org/v1.19/client-server-api/#oauth-20-api
762    AppserviceLoginUnsupported,
763
764    /// `M_BAD_ALIAS`
765    ///
766    /// One or more [room aliases] within the `m.room.canonical_alias` event do not point to the
767    /// room ID for which the state event is to be sent to.
768    ///
769    /// [room aliases]: https://spec.matrix.org/v1.19/client-server-api/#room-aliases
770    BadAlias,
771
772    /// `M_BAD_JSON`
773    ///
774    /// The request contained valid JSON, but it was malformed in some way, e.g. missing required
775    /// keys, invalid values for keys.
776    BadJson,
777
778    /// `M_BAD_STATE`
779    ///
780    /// The state change requested cannot be performed, such as attempting to unban a user who is
781    /// not banned.
782    BadState,
783
784    /// `M_BAD_STATUS`
785    ///
786    /// The application service returned a bad status.
787    BadStatus,
788
789    /// `M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
790    ///
791    /// The user is unable to reject an invite to join the [server notices] room.
792    ///
793    /// [server notices]: https://spec.matrix.org/v1.19/client-server-api/#server-notices
794    CannotLeaveServerNoticeRoom,
795
796    /// `M_CANNOT_OVERWRITE_MEDIA`
797    ///
798    /// The `PUT /_matrix/media/*/upload/{serverName}/{mediaId}` endpoint was called with a media ID
799    /// that already has content.
800    CannotOverwriteMedia,
801
802    /// `M_CAPTCHA_INVALID`
803    ///
804    /// The Captcha provided did not match what was expected.
805    CaptchaInvalid,
806
807    /// `M_CAPTCHA_NEEDED`
808    ///
809    /// A Captcha is required to complete the request.
810    CaptchaNeeded,
811
812    /// `M_CONCURRENT_WRITE`
813    ///
814    /// The sequence token provided when updating a rendezvous session
815    /// does not match the current sequence token.
816    ///
817    /// This uses the unstable prefix defined in [MSC4388].
818    ///
819    /// [MSC4388]: https://github.com/matrix-org/matrix-spec-proposals/pull/4388
820    #[cfg(feature = "unstable-msc4388")]
821    #[ruma_enum(rename = "IO_ELEMENT_MSC4388_CONCURRENT_WRITE")]
822    ConcurrentWrite,
823
824    /// `M_CONFLICTING_UNSUBSCRIPTION`
825    ///
826    /// Part of [MSC4306]: an automatic thread subscription has been skipped by the server, because
827    /// the user unsubsubscribed after the indicated subscribed-to event.
828    ///
829    /// [MSC4306]: https://github.com/matrix-org/matrix-spec-proposals/pull/4306
830    #[cfg(feature = "unstable-msc4306")]
831    #[ruma_enum(rename = "IO.ELEMENT.MSC4306.M_CONFLICTING_UNSUBSCRIPTION")]
832    ConflictingUnsubscription,
833
834    /// `M_CONNECTION_FAILED`
835    ///
836    /// The connection to the application service failed.
837    ConnectionFailed,
838
839    /// `M_CONNECTION_TIMEOUT`
840    ///
841    /// The connection to the application service timed out.
842    ConnectionTimeout,
843
844    /// `M_DUPLICATE_ANNOTATION`
845    ///
846    /// The request is an attempt to send a [duplicate annotation].
847    ///
848    /// [duplicate annotation]: https://spec.matrix.org/v1.19/client-server-api/#avoiding-duplicate-annotations
849    DuplicateAnnotation,
850
851    /// `M_EXCLUSIVE`
852    ///
853    /// The resource being requested is reserved by an application service, or the application
854    /// service making the request has not created the resource.
855    Exclusive,
856
857    /// `M_FORBIDDEN`
858    ///
859    /// Forbidden access, e.g. joining a room without permission, failed login.
860    Forbidden,
861
862    /// `M_GUEST_ACCESS_FORBIDDEN`
863    ///
864    /// The room or resource does not permit [guests] to access it.
865    ///
866    /// [guests]: https://spec.matrix.org/v1.19/client-server-api/#guest-access
867    GuestAccessForbidden,
868
869    /// `M_INCOMPATIBLE_ROOM_VERSION`
870    ///
871    /// The client attempted to join a room that has a version the server does not support.
872    IncompatibleRoomVersion,
873
874    /// `M_INSUFFICIENT_USER_AUTHENTICATION`
875    ///
876    /// The client needs to reauthenticate with the OAuth authorization server to use
877    /// this endpoint. ([MSC4363])
878    ///
879    /// [MSC4363]: https://github.com/matrix-org/matrix-spec-proposals/pull/4363
880    #[cfg(feature = "unstable-msc4363")]
881    #[ruma_enum(alias = "org.matrix.msc4363.M_INSUFFICIENT_USER_AUTHENTICATION")]
882    InsufficientUserAuthentication,
883
884    /// `M_INVALID_PARAM`
885    ///
886    /// A parameter that was specified has the wrong value. For example, the server expected an
887    /// integer and instead received a string.
888    InvalidParam,
889
890    /// `M_INVALID_ROOM_STATE`
891    ///
892    /// The initial state implied by the parameters to the `POST /_matrix/client/*/createRoom`
893    /// request is invalid, e.g. the user's `power_level` is set below that necessary to set the
894    /// room name.
895    InvalidRoomState,
896
897    /// `M_INVALID_USERNAME`
898    ///
899    /// The desired user name is not valid.
900    InvalidUsername,
901
902    /// `M_INVITE_BLOCKED`
903    ///
904    /// The invite was interdicted by moderation tools or configured access controls without having
905    /// been witnessed by the invitee.
906    ///
907    /// Unstable prefix intentionally shared with MSC4155 for compatibility.
908    #[ruma_enum(alias = "ORG.MATRIX.MSC4155.INVITE_BLOCKED")]
909    InviteBlocked,
910
911    /// `M_KEY_TOO_LARGE`
912    ///
913    /// The [profile] key in the request exceeds the maximum allowed length of 255 bytes.
914    ///
915    /// [profile]: https://spec.matrix.org/v1.19/client-server-api/#profiles
916    KeyTooLarge,
917
918    /// `M_LIMIT_EXCEEDED`
919    ///
920    /// The request has been refused due to [rate limiting]: too many requests have been sent in a
921    /// short period of time.
922    ///
923    /// [rate limiting]: https://spec.matrix.org/v1.19/client-server-api/#rate-limiting
924    LimitExceeded,
925
926    /// `M_MISSING_PARAM`
927    ///
928    /// A required parameter was missing from the request.
929    MissingParam,
930
931    /// `M_MISSING_TOKEN`
932    ///
933    /// No [access token] was specified for the request, but one is required.
934    ///
935    /// [access token]: https://spec.matrix.org/v1.19/client-server-api/#client-authentication
936    MissingToken,
937
938    /// `M_NOT_FOUND`
939    ///
940    /// No resource was found for this request.
941    NotFound,
942
943    /// `M_NOT_IN_THREAD`
944    ///
945    /// Part of [MSC4306]: an automatic thread subscription was set to an event ID that isn't part
946    /// of the subscribed-to thread.
947    ///
948    /// [MSC4306]: https://github.com/matrix-org/matrix-spec-proposals/pull/4306
949    #[cfg(feature = "unstable-msc4306")]
950    #[ruma_enum(rename = "IO.ELEMENT.MSC4306.M_NOT_IN_THREAD")]
951    NotInThread,
952
953    /// `M_NOT_JSON`
954    ///
955    /// The request did not contain valid JSON.
956    NotJson,
957
958    /// `M_NOT_YET_UPLOADED`
959    ///
960    /// An `mxc:` URI generated with the `POST /_matrix/media/*/create` endpoint was used and the
961    /// content is not yet available.
962    NotYetUploaded,
963
964    /// `M_PROFILE_TOO_LARGE`
965    ///
966    /// Storing the value in the request would make the [profile] exceed its maximum allowed size
967    /// of 64 KiB.
968    ///
969    /// [profile]: https://spec.matrix.org/v1.19/client-server-api/#profiles
970    ProfileTooLarge,
971
972    /// `M_RESOURCE_LIMIT_EXCEEDED`
973    ///
974    /// The request cannot be completed because the homeserver has reached a resource limit imposed
975    /// on it. For example, a homeserver held in a shared hosting environment may reach a resource
976    /// limit if it starts using too much memory or disk space.
977    ResourceLimitExceeded,
978
979    /// `M_ROOM_IN_USE`
980    ///
981    /// The [room alias] specified in the `POST /_matrix/client/*/createRoom` request is already
982    /// taken.
983    ///
984    /// [room alias]: https://spec.matrix.org/v1.19/client-server-api/#room-aliases
985    RoomInUse,
986
987    /// `M_SENDER_IGNORED`
988    ///
989    /// The sender of the requested event is ignored by the requesting user. ([MSC])
990    ///
991    /// [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/4406
992    #[cfg(feature = "unstable-msc4406")]
993    #[ruma_enum(rename = "UK.TIMEDOUT.MSC4406.SENDER_IGNORED")]
994    SenderIgnored,
995
996    /// `M_SERVER_NOT_TRUSTED`
997    ///
998    /// The client's request used a third-party server, e.g. identity server, that this server does
999    /// not trust.
1000    ServerNotTrusted,
1001
1002    /// `M_THREEPID_AUTH_FAILED`
1003    ///
1004    /// Authentication could not be performed on the [third-party identifier].
1005    ///
1006    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
1007    ThreepidAuthFailed,
1008
1009    /// `M_THREEPID_DENIED`
1010    ///
1011    /// The server does not permit this [third-party identifier]. This may happen if the server
1012    /// only permits, for example, email addresses from a particular domain.
1013    ///
1014    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
1015    ThreepidDenied,
1016
1017    /// `M_THREEPID_IN_USE`
1018    ///
1019    /// The [third-party identifier] is already in use by another user.
1020    ///
1021    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
1022    ThreepidInUse,
1023
1024    /// `M_THREEPID_MEDIUM_NOT_SUPPORTED`
1025    ///
1026    /// The homeserver does not support adding a [third-party identifier] of the given medium.
1027    ///
1028    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
1029    ThreepidMediumNotSupported,
1030
1031    /// `M_THREEPID_NOT_FOUND`
1032    ///
1033    /// No account matching the given [third-party identifier] could be found.
1034    ///
1035    /// [third-party identifier]: https://spec.matrix.org/v1.19/client-server-api/#adding-account-administrative-contact-information
1036    ThreepidNotFound,
1037
1038    /// `M_TOKEN_INCORRECT`
1039    ///
1040    /// The token that the user entered to validate the session is incorrect.
1041    TokenIncorrect,
1042
1043    /// `M_TOO_LARGE`
1044    ///
1045    /// The request or entity was too large.
1046    TooLarge,
1047
1048    /// `M_UNABLE_TO_AUTHORISE_JOIN`
1049    ///
1050    /// The room is [restricted] and none of the conditions can be validated by the homeserver.
1051    /// This can happen if the homeserver does not know about any of the rooms listed as
1052    /// conditions, for example.
1053    ///
1054    /// [restricted]: https://spec.matrix.org/v1.19/client-server-api/#restricted-rooms
1055    #[ruma_enum(rename = "M_UNABLE_TO_AUTHORISE_JOIN")]
1056    UnableToAuthorizeJoin,
1057
1058    /// `M_UNABLE_TO_GRANT_JOIN`
1059    ///
1060    /// A different server should be attempted for the join. This is typically because the resident
1061    /// server can see that the joining user satisfies one or more conditions, such as in the case
1062    /// of [restricted rooms], but the resident server would be unable to meet the authorization
1063    /// rules.
1064    ///
1065    /// [restricted rooms]: https://spec.matrix.org/v1.19/client-server-api/#restricted-rooms
1066    UnableToGrantJoin,
1067
1068    /// `M_UNACTIONABLE`
1069    ///
1070    /// The server does not want to handle the [federated report].
1071    ///
1072    /// [federated report]: https://github.com/matrix-org/matrix-spec-proposals/pull/3843
1073    #[cfg(feature = "unstable-msc3843")]
1074    Unactionable,
1075
1076    /// `M_UNAUTHORIZED`
1077    ///
1078    /// The request was not correctly authorized. Usually due to login failures.
1079    Unauthorized,
1080
1081    /// `M_UNKNOWN`
1082    ///
1083    /// An unknown error has occurred.
1084    Unknown,
1085
1086    /// `M_UNKNOWN_DEVICE`
1087    ///
1088    /// The device ID supplied by the application service does not belong to the user ID during
1089    /// [identity assertion].
1090    ///
1091    /// [identity assertion]: https://spec.matrix.org/v1.19/application-service-api/#identity-assertion
1092    UnknownDevice,
1093
1094    /// `M_UNKNOWN_POS`
1095    ///
1096    /// The sliding sync ([MSC4186]) connection was expired by the server.
1097    ///
1098    /// [MSC4186]: https://github.com/matrix-org/matrix-spec-proposals/pull/4186
1099    #[cfg(feature = "unstable-msc4186")]
1100    UnknownPos,
1101
1102    /// `M_UNKNOWN_TOKEN`
1103    ///
1104    /// The [access or refresh token] specified was not recognized.
1105    ///
1106    /// [access or refresh token]: https://spec.matrix.org/v1.19/client-server-api/#client-authentication
1107    UnknownToken,
1108
1109    /// `M_UNRECOGNIZED`
1110    ///
1111    /// The server did not understand the request.
1112    ///
1113    /// This is expected to be returned with a 404 HTTP status code if the endpoint is not
1114    /// implemented or a 405 HTTP status code if the endpoint is implemented, but the incorrect
1115    /// HTTP method is used.
1116    Unrecognized,
1117
1118    /// `M_UNSUPPORTED_ROOM_VERSION`
1119    UnsupportedRoomVersion,
1120
1121    /// `M_URL_NOT_SET`
1122    ///
1123    /// The application service doesn't have a URL configured.
1124    UrlNotSet,
1125
1126    /// `M_USER_DEACTIVATED`
1127    ///
1128    /// The user ID associated with the request has been deactivated.
1129    UserDeactivated,
1130
1131    /// `M_USER_IN_USE`
1132    ///
1133    /// The desired user ID is already taken.
1134    UserInUse,
1135
1136    /// `M_USER_LIMIT_EXCEEDED`
1137    ///
1138    /// The request cannot be completed because the user has exceeded (or the request would cause
1139    /// them to exceed) a limit associated with their account. For example, a user may have reached
1140    /// their allocated storage quota, reached a maximum number of allowed rooms, devices, or other
1141    /// account-scoped resources, or exceeded usage limits for specific features.
1142    UserLimitExceeded,
1143
1144    /// `M_USER_LOCKED`
1145    ///
1146    /// The account has been [locked] and cannot be used at this time.
1147    ///
1148    /// [locked]: https://spec.matrix.org/v1.19/client-server-api/#account-locking
1149    UserLocked,
1150
1151    /// `M_USER_SUSPENDED`
1152    ///
1153    /// The account has been [suspended] and can only be used for limited actions at this time.
1154    ///
1155    /// [suspended]: https://spec.matrix.org/v1.19/client-server-api/#account-suspension
1156    UserSuspended,
1157
1158    /// `M_WEAK_PASSWORD`
1159    ///
1160    /// The password was [rejected] by the server for being too weak.
1161    ///
1162    /// [rejected]: https://spec.matrix.org/v1.19/client-server-api/#password-management
1163    WeakPassword,
1164
1165    /// `M_WRONG_ROOM_KEYS_VERSION`
1166    ///
1167    /// The version of the [room keys backup] provided in the request does not match the current
1168    /// backup version.
1169    ///
1170    /// [room keys backup]: https://spec.matrix.org/v1.19/client-server-api/#server-side-key-backups
1171    WrongRoomKeysVersion,
1172
1173    #[doc(hidden)]
1174    _Custom(PrivOwnedStr),
1175}
1176
1177#[cfg(test)]
1178mod tests {
1179    use super::ErrorKind;
1180
1181    #[test]
1182    fn test_error_kind_type_size() {
1183        // There is no strict requirement for this type to be 40 bytes or smaller,
1184        // but it's been optimized by hand (Boxing the `_Custom` variant)
1185        // and it would be nice to keep track of any regressions.
1186        let size = size_of::<ErrorKind>();
1187        assert!(size <= 40, "size_of::<ErrorKind>() has regressed, is now {size}");
1188    }
1189}