Bug 1581173 part 1. Add a way to more easily throw TypeErrors and RangeErrors with custom message strings via ErrorResult. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 20 Sep 2019 02:19:18 +0000
changeset 494513 9d5377b224b3ea3f1c682f8e81ec99cda6e60b0f
parent 494512 31ca14d26fff74fe0cf971a8bb8784a0e0d49c35
child 494514 5f67fa6e2e9557b9e852ecc1a7e8c09c2df8d707
push id96050
push userbzbarsky@mozilla.com
push dateMon, 23 Sep 2019 14:00:19 +0000
treeherderautoland@5f67fa6e2e95 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1581173
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1581173 part 1. Add a way to more easily throw TypeErrors and RangeErrors with custom message strings via ErrorResult. r=smaug Differential Revision: https://phabricator.services.mozilla.com/D45932
dom/base/WindowNamedPropertiesHandler.cpp
dom/bindings/ErrorResult.h
dom/bindings/Errors.msg
dom/cache/CacheOpChild.cpp
dom/cache/ReadStream.cpp
dom/cache/TypeUtils.cpp
dom/fetch/InternalHeaders.cpp
dom/fetch/Request.cpp
dom/fetch/Response.cpp
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBFileHandle.cpp
dom/media/webaudio/AudioEventTimeline.h
dom/media/webaudio/PannerNode.h
dom/network/ConnectionWorker.cpp
dom/notification/Notification.cpp
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -143,17 +143,18 @@ bool WindowNamedPropertiesHandler::getOw
   return true;
 }
 
 bool WindowNamedPropertiesHandler::defineProperty(
     JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
     JS::Handle<JS::PropertyDescriptor> aDesc,
     JS::ObjectOpResult& result) const {
   ErrorResult rv;
-  rv.ThrowTypeError<MSG_DEFINEPROPERTY_ON_GSP>();
+  rv.ThrowTypeError(
+      u"Not allowed to define a property on the named properties object.");
   MOZ_ALWAYS_TRUE(rv.MaybeSetPendingException(aCx));
   return false;
 }
 
 bool WindowNamedPropertiesHandler::ownPropNames(
     JSContext* aCx, JS::Handle<JSObject*> aProxy, unsigned flags,
     JS::MutableHandleVector<jsid> aProps) const {
   if (!(flags & JSITER_HIDDEN)) {
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -282,22 +282,48 @@ class TErrorResult {
   void StealExceptionFromJSContext(JSContext* cx);
 
   template <dom::ErrNum errorNumber, typename... Ts>
   void ThrowTypeError(Ts&&... messageArgs) {
     ThrowErrorWithMessage<errorNumber>(NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR,
                                        std::forward<Ts>(messageArgs)...);
   }
 
+  // To be used when throwing a TypeError with a completely custom
+  // message string that's only used in one spot.
+  inline void ThrowTypeError(const nsAString& aMessage) {
+    this->template ThrowTypeError<dom::MSG_ONE_OFF_TYPEERR>(aMessage);
+  }
+
+  // To be used when throwing a TypeError with a completely custom
+  // message string that's a string literal that's only used in one spot.
+  template <int N>
+  void ThrowTypeError(const char16_t (&aMessage)[N]) {
+    ThrowTypeError(nsLiteralString(aMessage));
+  }
+
   template <dom::ErrNum errorNumber, typename... Ts>
   void ThrowRangeError(Ts&&... messageArgs) {
     ThrowErrorWithMessage<errorNumber>(NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR,
                                        std::forward<Ts>(messageArgs)...);
   }
 
+  // To be used when throwing a RangeError with a completely custom
+  // message string that's only used in one spot.
+  inline void ThrowRangeError(const nsAString& aMessage) {
+    this->template ThrowRangeError<dom::MSG_ONE_OFF_RANGEERR>(aMessage);
+  }
+
+  // To be used when throwing a RangeError with a completely custom
+  // message string that's a string literal that's only used in one spot.
+  template <int N>
+  void ThrowRangeError(const char16_t (&aMessage)[N]) {
+    ThrowRangeError(nsLiteralString(aMessage));
+  }
+
   bool IsErrorWithMessage() const {
     return ErrorCode() == NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR ||
            ErrorCode() == NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR;
   }
 
   // Facilities for throwing a preexisting JS exception value via this
   // TErrorResult.  The contract is that any code which might end up calling
   // ThrowJSException() or StealExceptionFromJSContext() must call
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -35,86 +35,60 @@ MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, JSEX
 MSG_DEF(MSG_ILLEGAL_TYPE_PR_CONSTRUCTOR, 1, JSEXN_TYPEERR, "TypeError:{0}")
 MSG_DEF(MSG_ILLEGAL_RANGE_PR_CONSTRUCTOR, 1, JSEXN_RANGEERR, "RangeError:{0}")
 MSG_DEF(MSG_CONSTRUCTOR_WITHOUT_NEW, 1, JSEXN_TYPEERR, "Constructor {0} requires 'new'")
 MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, JSEXN_TYPEERR, "Non-finite value is out of range for {0}.")
 MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "Value is out of range for {0}.")
 MSG_DEF(MSG_NOT_SEQUENCE, 1, JSEXN_TYPEERR, "{0} can't be converted to a sequence.")
 MSG_DEF(MSG_NOT_DICTIONARY, 1, JSEXN_TYPEERR, "{0} can't be converted to a dictionary.")
 MSG_DEF(MSG_OVERLOAD_RESOLUTION_FAILED, 3, JSEXN_TYPEERR, "Argument {0} is not valid for any of the {1}-argument overloads of {2}.")
-MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, JSEXN_TYPEERR, "Global is not a native object.")
 MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, JSEXN_RANGEERR, "The given encoding '{0}' is not supported.")
-MSG_DEF(MSG_DOM_ENCODING_NOT_UTF, 0, JSEXN_RANGEERR, "The encoding must be utf-8, utf-16, or utf-16be.")
 MSG_DEF(MSG_DOM_DECODING_FAILED, 0, JSEXN_TYPEERR, "Decoding failed.")
 MSG_DEF(MSG_NOT_FINITE, 1, JSEXN_TYPEERR, "{0} is not a finite floating-point value.")
-MSG_DEF(MSG_INVALID_VERSION, 0, JSEXN_TYPEERR, "0 (Zero) is not a valid database version.")
 MSG_DEF(MSG_INVALID_BYTESTRING, 2, JSEXN_TYPEERR, "Cannot convert string to ByteString because the character"
         " at index {0} has value {1} which is greater than 255.")
 MSG_DEF(MSG_NOT_DATE, 1, JSEXN_TYPEERR, "{0} is not a date.")
-MSG_DEF(MSG_INVALID_ADVANCE_COUNT, 0, JSEXN_TYPEERR, "0 (Zero) is not a valid advance count.")
-MSG_DEF(MSG_DEFINEPROPERTY_ON_GSP, 0, JSEXN_TYPEERR, "Not allowed to define a property on the named properties object.")
 MSG_DEF(MSG_INVALID_URL, 1, JSEXN_TYPEERR, "{0} is not a valid URL.")
 MSG_DEF(MSG_URL_HAS_CREDENTIALS, 1, JSEXN_TYPEERR, "{0} is an url with embedded credentials.")
-MSG_DEF(MSG_METADATA_NOT_CONFIGURED, 0, JSEXN_TYPEERR, "Either size or lastModified should be true.")
-MSG_DEF(MSG_INVALID_READ_SIZE, 0, JSEXN_TYPEERR, "0 (Zero) is not a valid read size.")
-MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, JSEXN_TYPEERR, "Headers are immutable and cannot be modified.")
 MSG_DEF(MSG_INVALID_HEADER_NAME, 1, JSEXN_TYPEERR, "{0} is an invalid header name.")
 MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, JSEXN_TYPEERR, "{0} is an invalid header value.")
-MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, JSEXN_TYPEERR, "Headers require name/value tuples when being initialized by a sequence.")
 MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, JSEXN_TYPEERR, "Permission denied to pass cross-origin object as {0}.")
 MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, JSEXN_TYPEERR, "Missing required {0}.")
-MSG_DEF(MSG_REQUEST_INTEGRITY_METADATA_NOT_EMPTY, 0, JSEXN_TYPEERR, "Request integrity metadata should be an empty string when in no-cors mode.")
 MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, JSEXN_TYPEERR, "Invalid request method {0}.")
 MSG_DEF(MSG_INVALID_REQUEST_MODE, 1, JSEXN_TYPEERR, "Invalid request mode {0}.")
 MSG_DEF(MSG_INVALID_REFERRER_URL, 1, JSEXN_TYPEERR, "Invalid referrer URL {0}.")
 MSG_DEF(MSG_CROSS_ORIGIN_REFERRER_URL, 2, JSEXN_TYPEERR, "Referrer URL {0} cannot be cross-origin to the entry settings object ({1}).")
 MSG_DEF(MSG_FETCH_BODY_CONSUMED_ERROR, 0, JSEXN_TYPEERR, "Body has already been consumed.")
 MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, JSEXN_TYPEERR, "Response statusText may not contain newline or carriage return.")
 MSG_DEF(MSG_FETCH_FAILED, 0, JSEXN_TYPEERR, "NetworkError when attempting to fetch resource.")
-MSG_DEF(MSG_NO_BODY_ALLOWED_FOR_GET_AND_HEAD, 0, JSEXN_TYPEERR, "HEAD or GET Request cannot have a body.")
-MSG_DEF(MSG_RESPONSE_NULL_STATUS_WITH_BODY, 0, JSEXN_TYPEERR, "Response body is given with a null body status.")
-MSG_DEF(MSG_DEFINE_NON_CONFIGURABLE_PROP_ON_WINDOW, 0, JSEXN_TYPEERR, "Not allowed to define a non-configurable property on the WindowProxy object")
 MSG_DEF(MSG_INVALID_ZOOMANDPAN_VALUE_ERROR, 0, JSEXN_RANGEERR, "Invalid zoom and pan value.")
 MSG_DEF(MSG_INVALID_TRANSFORM_ANGLE_ERROR, 0, JSEXN_RANGEERR, "Invalid transform angle.")
-MSG_DEF(MSG_INVALID_RESPONSE_STATUSCODE_ERROR, 0, JSEXN_RANGEERR, "Invalid response status code.")
-MSG_DEF(MSG_INVALID_REDIRECT_STATUSCODE_ERROR, 0, JSEXN_RANGEERR, "Invalid redirect status code.")
 MSG_DEF(MSG_INVALID_URL_SCHEME, 2, JSEXN_TYPEERR, "{0} URL {1} must be either http:// or https://.")
-MSG_DEF(MSG_RESPONSE_URL_IS_NULL, 0, JSEXN_TYPEERR, "Cannot set Response.finalURL when Response.url is null.")
-MSG_DEF(MSG_RESPONSE_HAS_VARY_STAR, 0, JSEXN_TYPEERR, "Invalid Response object with a 'Vary: *' header.")
 MSG_DEF(MSG_BAD_FORMDATA, 0, JSEXN_TYPEERR, "Could not parse content as FormData.")
 MSG_DEF(MSG_NO_ACTIVE_WORKER, 1, JSEXN_TYPEERR, "No active worker for scope {0}.")
-MSG_DEF(MSG_NOTIFICATION_PERMISSION_DENIED, 0, JSEXN_TYPEERR, "Permission to show Notification denied.")
-MSG_DEF(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER, 0, JSEXN_TYPEERR, "Notification constructor cannot be used in ServiceWorkerGlobalScope. Use registration.showNotification() instead.")
 MSG_DEF(MSG_INVALID_SCOPE, 2, JSEXN_TYPEERR, "Invalid scope trying to resolve {0} with base URL {1}.")
 MSG_DEF(MSG_INVALID_KEYFRAME_OFFSETS, 0, JSEXN_TYPEERR, "Keyframes with specified offsets must be in order and all be in the range [0, 1].")
 MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise")
 MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.")
 MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.")
 MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer")
 MSG_DEF(MSG_TYPEDARRAY_IS_DETACHED, 1, JSEXN_TYPEERR, "{0} can't be a detached buffer")
 MSG_DEF(MSG_CACHE_ADD_FAILED_RESPONSE, 3, JSEXN_TYPEERR, "Cache got {0} response with bad status {1} while trying to add request {2}")
 MSG_DEF(MSG_SW_UPDATE_BAD_REGISTRATION, 2, JSEXN_TYPEERR, "Failed to update the ServiceWorker for scope {0} because the registration has been {1} since the update was scheduled.")
 MSG_DEF(MSG_INVALID_DURATION_ERROR, 1, JSEXN_TYPEERR, "Invalid duration '{0}'.")
 MSG_DEF(MSG_INVALID_EASING_ERROR, 1, JSEXN_TYPEERR, "Invalid easing '{0}'.")
 MSG_DEF(MSG_USELESS_SETTIMEOUT, 1, JSEXN_TYPEERR, "Useless {0} call (missing quotes around argument?)")
 MSG_DEF(MSG_TOKENLIST_NO_SUPPORTED_TOKENS, 2, JSEXN_TYPEERR, "{0} attribute of <{1}> does not define any supported tokens")
-MSG_DEF(MSG_CACHE_STREAM_CLOSED, 0, JSEXN_TYPEERR, "Response body is a cache file stream that has already been closed.")
 MSG_DEF(MSG_TIME_VALUE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "{0} is outside the supported range for time values.")
 MSG_DEF(MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN, 1, JSEXN_TYPEERR, "Request mode '{0}' was used, but request cache mode 'only-if-cached' can only be used with request mode 'same-origin'.")
 MSG_DEF(MSG_THRESHOLD_RANGE_ERROR, 0, JSEXN_RANGEERR, "Threshold values must all be in the range [0, 1].")
-MSG_DEF(MSG_WORKER_THREAD_SHUTTING_DOWN, 0, JSEXN_TYPEERR, "The Worker thread is shutting down.")
-MSG_DEF(MSG_CACHE_OPEN_FAILED, 0, JSEXN_TYPEERR, "CacheStorage.open() failed to access the storage system.")
 MSG_DEF(MSG_MATRIX_INIT_CONFLICTING_VALUE, 2, JSEXN_TYPEERR, "Matrix init unexpectedly got different values for '{0}' and '{1}'.")
 MSG_DEF(MSG_MATRIX_INIT_EXCEEDS_2D, 1, JSEXN_TYPEERR, "Matrix init has an unexpected 3D element '{0}' which cannot coexist with 'is2D: true'.")
 MSG_DEF(MSG_MATRIX_INIT_LENGTH_WRONG, 1, JSEXN_TYPEERR, "Matrix init sequence must have a length of 6 or 16 (actual value: {0})")
 MSG_DEF(MSG_INVALID_MEDIA_VIDEO_CONFIGURATION, 0, JSEXN_TYPEERR, "Invalid VideoConfiguration.")
 MSG_DEF(MSG_INVALID_MEDIA_AUDIO_CONFIGURATION, 0, JSEXN_TYPEERR, "Invalid AudioConfiguration.")
-MSG_DEF(MSG_INVALID_CURVE_DURATION_ERROR, 0, JSEXN_RANGEERR, "The curve duration for setValueCurveAtTime must be strictly positive.")
 MSG_DEF(MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR, 0, JSEXN_RANGEERR, "The start time for an AudioParam method must be non-negative.")
 MSG_DEF(MSG_INVALID_AUDIOPARAM_METHOD_END_TIME_ERROR, 0, JSEXN_RANGEERR, "The end time for an AudioParam method must be non-negative.")
-MSG_DEF(MSG_INVALID_AUDIOPARAM_EXPONENTIAL_VALUE_ERROR, 0, JSEXN_RANGEERR, "The value passed to exponentialRampToValueAtTime must be positive.")
-MSG_DEF(MSG_INVALID_AUDIOPARAM_EXPONENTIAL_CONSTANT_ERROR, 0, JSEXN_RANGEERR, "The exponential constant passed to setTargetAtTime must be non-negative.")
 MSG_DEF(MSG_VALUE_OUT_OF_RANGE, 1, JSEXN_RANGEERR, "The value for the {0} is outside the valid range.")
-MSG_DEF(MSG_INVALID_PANNERNODE_REFDISTANCE_ERROR, 0, JSEXN_RANGEERR, "The refDistance value passed to PannerNode must not be negative.")
-MSG_DEF(MSG_INVALID_PANNERNODE_MAXDISTANCE_ERROR, 0, JSEXN_RANGEERR, "The maxDistance value passed to PannerNode must be positive.")
-MSG_DEF(MSG_INVALID_PANNERNODE_ROLLOFF_ERROR, 0, JSEXN_RANGEERR, "The rolloffFactor value passed to PannerNode must not be negative.")
 MSG_DEF(MSG_NOT_ARRAY_NOR_UNDEFINED, 1, JSEXN_TYPEERR, "{0} is neither an array nor undefined.")
 MSG_DEF(MSG_URL_NOT_LOADABLE, 1, JSEXN_TYPEERR, "Access to '{0}' from script denied.")
+MSG_DEF(MSG_ONE_OFF_TYPEERR, 1, JSEXN_TYPEERR, "{0}")
+MSG_DEF(MSG_ONE_OFF_RANGEERR, 1, JSEXN_RANGEERR, "{0}")
--- a/dom/cache/CacheOpChild.cpp
+++ b/dom/cache/CacheOpChild.cpp
@@ -136,17 +136,18 @@ mozilla::ipc::IPCResult CacheOpChild::Re
       auto result = aResult.get_StorageOpenResult();
       auto actor = static_cast<CacheChild*>(result.actorChild());
 
       // If we have a success status then we should have an actor.  Gracefully
       // reject instead of crashing, though, if we get a nullptr here.
       MOZ_DIAGNOSTIC_ASSERT(actor);
       if (!actor) {
         ErrorResult status;
-        status.ThrowTypeError<MSG_CACHE_OPEN_FAILED>();
+        status.ThrowTypeError(
+            u"CacheStorage.open() failed to access the storage system.");
         mPromise->MaybeReject(status);
         break;
       }
 
       RefPtr<CacheWorkerRef> workerRef = CacheWorkerRef::PreferBehavior(
           GetWorkerRef(), CacheWorkerRef::eIPCWorkerRef);
 
       actor->SetWorkerRef(workerRef);
--- a/dom/cache/ReadStream.cpp
+++ b/dom/cache/ReadStream.cpp
@@ -203,17 +203,18 @@ void ReadStream::Inner::Serialize(
 
 void ReadStream::Inner::Serialize(
     CacheReadStream* aReadStreamOut,
     nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList, ErrorResult& aRv) {
   MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
   MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
 
   if (mState != Open) {
-    aRv.ThrowTypeError<MSG_CACHE_STREAM_CLOSED>();
+    aRv.ThrowTypeError(
+        u"Response body is a cache file stream that has already been closed.");
     return;
   }
 
   MOZ_DIAGNOSTIC_ASSERT(mControl);
 
   aReadStreamOut->id() = mId;
   mControl->SerializeControl(aReadStreamOut);
 
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -180,17 +180,17 @@ void TypeUtils::ToCacheResponseWithoutBo
     ProcessURL(aOut.urlList()[i], nullptr, nullptr, nullptr, aRv);
   }
 
   aOut.status() = aIn.GetUnfilteredStatus();
   aOut.statusText() = aIn.GetUnfilteredStatusText();
   RefPtr<InternalHeaders> headers = aIn.UnfilteredHeaders();
   MOZ_DIAGNOSTIC_ASSERT(headers);
   if (HasVaryStar(headers)) {
-    aRv.ThrowTypeError<MSG_RESPONSE_HAS_VARY_STAR>();
+    aRv.ThrowTypeError(u"Invalid Response object with a 'Vary: *' header.");
     return;
   }
   ToHeadersEntryList(aOut.headers(), headers);
   aOut.headersGuard() = headers->Guard();
   aOut.channelInfo() = aIn.GetChannelInfo().AsIPCChannelInfo();
   if (aIn.GetPrincipalInfo()) {
     aOut.principalInfo() = Some(*aIn.GetPrincipalInfo());
   } else {
--- a/dom/fetch/InternalHeaders.cpp
+++ b/dom/fetch/InternalHeaders.cpp
@@ -372,17 +372,17 @@ bool InternalHeaders::IsInvalidValue(con
     aRv.ThrowTypeError<MSG_INVALID_HEADER_VALUE>(label);
     return true;
   }
   return false;
 }
 
 bool InternalHeaders::IsImmutable(ErrorResult& aRv) const {
   if (mGuard == HeadersGuardEnum::Immutable) {
-    aRv.ThrowTypeError<MSG_HEADERS_IMMUTABLE>();
+    aRv.ThrowTypeError(u"Headers are immutable and cannot be modified.");
     return true;
   }
   return false;
 }
 
 bool InternalHeaders::IsForbiddenRequestHeader(const nsCString& aName) const {
   return mGuard == HeadersGuardEnum::Request &&
          nsContentUtils::IsForbiddenRequestHeader(aName);
@@ -413,17 +413,19 @@ void InternalHeaders::Fill(const Interna
   }
 }
 
 void InternalHeaders::Fill(const Sequence<Sequence<nsCString>>& aInit,
                            ErrorResult& aRv) {
   for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
     const Sequence<nsCString>& tuple = aInit[i];
     if (tuple.Length() != 2) {
-      aRv.ThrowTypeError<MSG_INVALID_HEADER_SEQUENCE>();
+      aRv.ThrowTypeError(
+          u"Headers require name/value tuples when being initialized by a "
+          u"sequence.");
       return;
     }
     Append(tuple[0], tuple[1], aRv);
   }
 }
 
 void InternalHeaders::Fill(const Record<nsCString, nsCString>& aInit,
                            ErrorResult& aRv) {
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -536,17 +536,17 @@ already_AddRefed<Request> Request::Const
 
   if ((aInit.mBody.WasPassed() && !aInit.mBody.Value().IsNull()) ||
       hasCopiedBody) {
     // HEAD and GET are not allowed to have a body.
     nsAutoCString method;
     request->GetMethod(method);
     // method is guaranteed to be uppercase due to step 14.2 above.
     if (method.EqualsLiteral("HEAD") || method.EqualsLiteral("GET")) {
-      aRv.ThrowTypeError<MSG_NO_BODY_ALLOWED_FOR_GET_AND_HEAD>();
+      aRv.ThrowTypeError(u"HEAD or GET Request cannot have a body.");
       return nullptr;
     }
   }
 
   if (aInit.mBody.WasPassed()) {
     const Nullable<fetch::OwningBodyInit>& bodyInitNullable =
         aInit.mBody.Value();
     if (!bodyInitNullable.IsNull()) {
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -131,17 +131,17 @@ already_AddRefed<Response> Response::Red
       return nullptr;
     }
 
     url->Stringify(parsedURL);
   }
 
   if (aStatus != 301 && aStatus != 302 && aStatus != 303 && aStatus != 307 &&
       aStatus != 308) {
-    aRv.ThrowRangeError<MSG_INVALID_REDIRECT_STATUSCODE_ERROR>();
+    aRv.ThrowRangeError(u"Invalid redirect status code.");
     return nullptr;
   }
 
   // We can't just pass nullptr for our null-valued Nullable, because the
   // fetch::ResponseBodyInit is a non-temporary type due to the MOZ_RAII
   // annotations on some of its members.
   Nullable<fetch::ResponseBodyInit> body;
   ResponseInit init;
@@ -170,17 +170,17 @@ already_AddRefed<Response> Response::Con
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 
   if (NS_WARN_IF(!global)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   if (aInit.mStatus < 200 || aInit.mStatus > 599) {
-    aRv.ThrowRangeError<MSG_INVALID_RESPONSE_STATUSCODE_ERROR>();
+    aRv.ThrowRangeError(u"Invalid response status code.");
     return nullptr;
   }
 
   // Check if the status text contains illegal characters
   nsACString::const_iterator start, end;
   aInit.mStatusText.BeginReading(start);
   aInit.mStatusText.EndReading(end);
   if (FindCharInReadable('\r', start, end)) {
@@ -258,17 +258,17 @@ already_AddRefed<Response> Response::Con
     internalResponse->Headers()->Fill(*headers->GetInternalHeaders(), aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
   if (!aBody.IsNull()) {
     if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
-      aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
+      aRv.ThrowTypeError(u"Response body is given with a null body status.");
       return nullptr;
     }
 
     nsCString contentTypeWithCharset;
     nsCOMPtr<nsIInputStream> bodyStream;
     int64_t bodySize = InternalResponse::UNKNOWN_BODY_SIZE;
 
     const fetch::ResponseBodyInit& body = aBody.Value();
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -565,17 +565,17 @@ void IDBCursor::ContinuePrimaryKey(JSCon
 
   mContinueCalled = true;
 }
 
 void IDBCursor::Advance(uint32_t aCount, ErrorResult& aRv) {
   AssertIsOnOwningThread();
 
   if (!aCount) {
-    aRv.ThrowTypeError<MSG_INVALID_ADVANCE_COUNT>();
+    aRv.ThrowTypeError(u"0 (Zero) is not a valid advance count.");
     return;
   }
 
   if (!mTransaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return;
   }
 
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -626,17 +626,17 @@ already_AddRefed<IDBOpenDBRequest> IDBFa
     }
   } else {
     principalInfo = *mPrincipalInfo;
   }
 
   uint64_t version = 0;
   if (!aDeleting && aVersion.WasPassed()) {
     if (aVersion.Value() < 1) {
-      aRv.ThrowTypeError<MSG_INVALID_VERSION>();
+      aRv.ThrowTypeError(u"0 (Zero) is not a valid database version.");
       return nullptr;
     }
     version = aVersion.Value();
   }
 
   // Nothing can be done here if we have previously failed to create a
   // background actor.
   if (mBackgroundActorFailed) {
--- a/dom/indexedDB/IDBFileHandle.cpp
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -266,17 +266,17 @@ already_AddRefed<IDBFileRequest> IDBFile
 
   // Common state checking
   if (!CheckState(aRv)) {
     return nullptr;
   }
 
   // Argument checking for get metadata.
   if (!aParameters.mSize && !aParameters.mLastModified) {
-    aRv.ThrowTypeError<MSG_METADATA_NOT_CONFIGURED>();
+    aRv.ThrowTypeError(u"Either size or lastModified should be true.");
     return nullptr;
   }
 
   // Do nothing if the window is closed
   if (!CheckWindow()) {
     return nullptr;
   }
 
@@ -387,17 +387,17 @@ bool IDBFileHandle::CheckStateAndArgumen
   // Additional state checking for read
   if (mLocation == UINT64_MAX) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
     return false;
   }
 
   // Argument checking for read
   if (!aSize) {
-    aRv.ThrowTypeError<MSG_INVALID_READ_SIZE>();
+    aRv.ThrowTypeError(u"0 (Zero) is not a valid read size.");
     return false;
   }
 
   return true;
 }
 
 bool IDBFileHandle::CheckStateForWrite(ErrorResult& aRv) {
   // Common state checking
--- a/dom/media/webaudio/AudioEventTimeline.h
+++ b/dom/media/webaudio/AudioEventTimeline.h
@@ -123,27 +123,31 @@ class AudioEventTimeline {
     };
 
     // Validate the event itself
     if (!WebAudioUtils::IsTimeValid(TimeOf(aEvent))) {
       aRv.ThrowRangeError<MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>();
       return false;
     }
     if (!WebAudioUtils::IsTimeValid(aEvent.mTimeConstant)) {
-      aRv.ThrowRangeError<MSG_INVALID_AUDIOPARAM_EXPONENTIAL_CONSTANT_ERROR>();
+      aRv.ThrowRangeError(
+          u"The exponential constant passed to setTargetAtTime must be "
+          u"non-negative.");
       return false;
     }
 
     if (aEvent.mType == AudioTimelineEvent::SetValueCurve) {
       if (!aEvent.mCurve || aEvent.mCurveLength < 2) {
         aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
         return false;
       }
       if (aEvent.mDuration <= 0) {
-        aRv.ThrowRangeError<MSG_INVALID_CURVE_DURATION_ERROR>();
+        aRv.ThrowRangeError(
+            u"The curve duration for setValueCurveAtTime must be strictly "
+            u"positive.");
         return false;
       }
     }
 
     MOZ_ASSERT(IsValid(aEvent.mValue) && IsValid(aEvent.mDuration));
 
     // Make sure that new events don't fall within the duration of a
     // curve event.
@@ -166,17 +170,19 @@ class AudioEventTimeline {
           return false;
         }
       }
     }
 
     // Make sure that invalid values are not used for exponential curves
     if (aEvent.mType == AudioTimelineEvent::ExponentialRamp) {
       if (aEvent.mValue <= 0.f) {
-        aRv.ThrowRangeError<MSG_INVALID_AUDIOPARAM_EXPONENTIAL_VALUE_ERROR>();
+        aRv.ThrowRangeError(
+            u"The value passed to exponentialRampToValueAtTime must be "
+            u"positive.");
         return false;
       }
       const AudioTimelineEvent* previousEvent =
           GetPreviousEvent(TimeOf(aEvent));
       if (previousEvent) {
         if (previousEvent->mValue <= 0.f) {
           aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
           return false;
--- a/dom/media/webaudio/PannerNode.h
+++ b/dom/media/webaudio/PannerNode.h
@@ -89,47 +89,51 @@ class PannerNode final : public AudioNod
 
   double RefDistance() const { return mRefDistance; }
   void SetRefDistance(double aRefDistance, ErrorResult& aRv) {
     if (WebAudioUtils::FuzzyEqual(mRefDistance, aRefDistance)) {
       return;
     }
 
     if (aRefDistance < 0) {
-      aRv.template ThrowRangeError<MSG_INVALID_PANNERNODE_REFDISTANCE_ERROR>();
+      aRv.ThrowRangeError(
+          u"The refDistance value passed to PannerNode must not be negative.");
       return;
     }
 
     mRefDistance = aRefDistance;
     SendDoubleParameterToStream(REF_DISTANCE, mRefDistance);
   }
 
   double MaxDistance() const { return mMaxDistance; }
   void SetMaxDistance(double aMaxDistance, ErrorResult& aRv) {
     if (WebAudioUtils::FuzzyEqual(mMaxDistance, aMaxDistance)) {
       return;
     }
 
     if (aMaxDistance <= 0) {
-      aRv.template ThrowRangeError<MSG_INVALID_PANNERNODE_MAXDISTANCE_ERROR>();
+      aRv.ThrowRangeError(
+          u"The maxDistance value passed to PannerNode must be positive.");
       return;
     }
 
     mMaxDistance = aMaxDistance;
     SendDoubleParameterToStream(MAX_DISTANCE, mMaxDistance);
   }
 
   double RolloffFactor() const { return mRolloffFactor; }
   void SetRolloffFactor(double aRolloffFactor, ErrorResult& aRv) {
     if (WebAudioUtils::FuzzyEqual(mRolloffFactor, aRolloffFactor)) {
       return;
     }
 
     if (aRolloffFactor < 0) {
-      aRv.template ThrowRangeError<MSG_INVALID_PANNERNODE_ROLLOFF_ERROR>();
+      aRv.ThrowRangeError(
+          u"The rolloffFactor value passed to PannerNode must not be "
+          u"negative.");
     }
 
     mRolloffFactor = aRolloffFactor;
     SendDoubleParameterToStream(ROLLOFF_FACTOR, mRolloffFactor);
   }
 
   double ConeInnerAngle() const { return mConeInnerAngle; }
   void SetConeInnerAngle(double aConeInnerAngle) {
--- a/dom/network/ConnectionWorker.cpp
+++ b/dom/network/ConnectionWorker.cpp
@@ -140,17 +140,17 @@ class NotifyRunnable : public WorkerRunn
 }  // anonymous namespace
 
 /* static */
 already_AddRefed<ConnectionWorker> ConnectionWorker::Create(
     WorkerPrivate* aWorkerPrivate, ErrorResult& aRv) {
   RefPtr<ConnectionWorker> c = new ConnectionWorker();
   c->mProxy = ConnectionProxy::Create(aWorkerPrivate, c);
   if (!c->mProxy) {
-    aRv.ThrowTypeError<MSG_WORKER_THREAD_SHUTTING_DOWN>();
+    aRv.ThrowTypeError(u"The Worker thread is shutting down.");
     return nullptr;
   }
 
   hal::NetworkInformation networkInfo;
   RefPtr<InitializeRunnable> runnable =
       new InitializeRunnable(aWorkerPrivate, c->mProxy, networkInfo);
 
   runnable->Dispatch(Canceling, aRv);
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -875,17 +875,19 @@ void Notification::SetAlertName() {
 // static
 already_AddRefed<Notification> Notification::Constructor(
     const GlobalObject& aGlobal, const nsAString& aTitle,
     const NotificationOptions& aOptions, ErrorResult& aRv) {
   // FIXME(nsm): If the sticky flag is set, throw an error.
   RefPtr<ServiceWorkerGlobalScope> scope;
   UNWRAP_OBJECT(ServiceWorkerGlobalScope, aGlobal.Get(), scope);
   if (scope) {
-    aRv.ThrowTypeError<MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER>();
+    aRv.ThrowTypeError(
+        u"Notification constructor cannot be used in ServiceWorkerGlobalScope. "
+        u"Use registration.showNotification() instead.");
     return nullptr;
   }
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<Notification> notification = CreateAndShow(
       aGlobal.Context(), global, aTitle, aOptions, EmptyString(), aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -2277,17 +2279,17 @@ already_AddRefed<Promise> Notification::
   // which leads to uglier code.
   NotificationPermission permission = GetPermission(aGlobal, aRv);
 
   // "If permission for notification's origin is not "granted", reject promise
   // with a TypeError exception, and terminate these substeps."
   if (NS_WARN_IF(aRv.Failed()) ||
       permission == NotificationPermission::Denied) {
     ErrorResult result;
-    result.ThrowTypeError<MSG_NOTIFICATION_PERMISSION_DENIED>();
+    result.ThrowTypeError(u"Permission to show Notification denied.");
     p->MaybeReject(result);
     return p.forget();
   }
 
   // "Otherwise, resolve promise with undefined."
   // The Notification may still not be shown due to other errors, but the spec
   // is not concerned with those.
   p->MaybeResolveWithUndefined();