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}