diff --git a/doc/api/errors.md b/doc/api/errors.md
index fcc39ab2ac81ee..498fc856ad5b19 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1116,6 +1116,11 @@ API] [`URLSearchParams` constructor][`new URLSearchParams(iterable)`] does not
represent a `[name, value]` tuple – that is, if an element is not iterable, or
does not consist of exactly two elements.
+
+### ERR_INVALID_URI
+
+Used when an invalid URI is passed.
+
### ERR_INVALID_URL
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 9bf0951eece120..fc6b11a40e9d1f 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -126,6 +126,7 @@ module.exports = exports = {
Error: makeNodeError(Error),
TypeError: makeNodeError(TypeError),
RangeError: makeNodeError(RangeError),
+ URIError: makeNodeError(URIError),
AssertionError,
E // This is exported only to facilitate testing.
};
@@ -287,6 +288,7 @@ E('ERR_INVALID_SYNC_FORK_INPUT',
'Asynchronous forks do not support Buffer, Uint8Array or string input: %s');
E('ERR_INVALID_THIS', 'Value of "this" must be of type %s');
E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple');
+E('ERR_INVALID_URI', 'URI malformed');
E('ERR_INVALID_URL', 'Invalid URL: %s');
E('ERR_INVALID_URL_SCHEME',
(expected) => `The URL must be ${oneOf(expected, 'scheme')}`);
diff --git a/lib/querystring.js b/lib/querystring.js
index 936b7463c9e5f6..ec6ad51a89177e 100644
--- a/lib/querystring.js
+++ b/lib/querystring.js
@@ -24,6 +24,7 @@
'use strict';
const { Buffer } = require('buffer');
+const errors = require('internal/errors');
const {
hexTable,
isHexTable
@@ -174,11 +175,12 @@ function qsEscape(str) {
}
// Surrogate pair
++i;
- var c2;
- if (i < str.length)
- c2 = str.charCodeAt(i) & 0x3FF;
- else
- throw new URIError('URI malformed');
+
+ if (i >= str.length)
+ throw new errors.URIError('ERR_INVALID_URI');
+
+ var c2 = str.charCodeAt(i) & 0x3FF;
+
lastPos = i + 1;
c = 0x10000 + (((c & 0x3FF) << 10) | c2);
out += hexTable[0xF0 | (c >> 18)] +
diff --git a/test/parallel/test-querystring-escape.js b/test/parallel/test-querystring-escape.js
index fd20a8424fee96..18bece1ab13288 100644
--- a/test/parallel/test-querystring-escape.js
+++ b/test/parallel/test-querystring-escape.js
@@ -1,5 +1,5 @@
'use strict';
-require('../common');
+const common = require('../common');
const assert = require('assert');
const qs = require('querystring');
@@ -12,8 +12,15 @@ assert.deepStrictEqual(qs.escape('Ŋōđĕ'), '%C5%8A%C5%8D%C4%91%C4%95');
assert.deepStrictEqual(qs.escape('testŊōđĕ'), 'test%C5%8A%C5%8D%C4%91%C4%95');
assert.deepStrictEqual(qs.escape(`${String.fromCharCode(0xD800 + 1)}test`),
'%F0%90%91%B4est');
-assert.throws(() => qs.escape(String.fromCharCode(0xD800 + 1)),
- /^URIError: URI malformed$/);
+
+common.expectsError(
+ () => qs.escape(String.fromCharCode(0xD800 + 1)),
+ {
+ code: 'ERR_INVALID_URI',
+ type: URIError,
+ message: 'URI malformed'
+ }
+);
// using toString for objects
assert.strictEqual(
diff --git a/test/parallel/test-querystring.js b/test/parallel/test-querystring.js
index ed0138e07937ef..400431fd2cb132 100644
--- a/test/parallel/test-querystring.js
+++ b/test/parallel/test-querystring.js
@@ -20,7 +20,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
-require('../common');
+const common = require('../common');
const assert = require('assert');
const inspect = require('util').inspect;
@@ -271,9 +271,14 @@ qsWeirdObjects.forEach(function(testCase) {
});
// invalid surrogate pair throws URIError
-assert.throws(function() {
- qs.stringify({ foo: '\udc00' });
-}, /^URIError: URI malformed$/);
+common.expectsError(
+ () => qs.stringify({ foo: '\udc00' }),
+ {
+ code: 'ERR_INVALID_URI',
+ type: URIError,
+ message: 'URI malformed'
+ }
+);
// coerce numbers to string
assert.strictEqual('foo=0', qs.stringify({ foo: 0 }));