diff --git a/services/dynamic/dynamic-json.service.js b/services/dynamic/dynamic-json.service.js
index af27ef069d8defc3eccf295bb3c2d47f53882456..edb2eaa3c1b0417c2d4e1a1be76003abb0e3d4b6 100644
--- a/services/dynamic/dynamic-json.service.js
+++ b/services/dynamic/dynamic-json.service.js
@@ -4,7 +4,7 @@ const Joi = require('@hapi/joi')
 const jp = require('jsonpath')
 const { renderDynamicBadge, errorMessages } = require('../dynamic-common')
 const { createRoute } = require('./dynamic-helpers')
-const { BaseJsonService, InvalidResponse } = require('..')
+const { BaseJsonService, InvalidParameter, InvalidResponse } = require('..')
 
 module.exports = class DynamicJson extends BaseJsonService {
   static get category() {
@@ -28,7 +28,18 @@ module.exports = class DynamicJson extends BaseJsonService {
       errorMessages,
     })
 
-    const values = jp.query(data, pathExpression)
+    let values
+    try {
+      values = jp.query(data, pathExpression)
+    } catch (e) {
+      if (e.message.startsWith('Lexical error')) {
+        throw new InvalidParameter({
+          prettyMessage: 'unparseable jsonpath query',
+        })
+      } else {
+        throw e
+      }
+    }
 
     if (!values.length) {
       throw new InvalidResponse({ prettyMessage: 'no result' })
diff --git a/services/dynamic/dynamic-json.tester.js b/services/dynamic/dynamic-json.tester.js
index 605748af2ac9486abc33bdef91226e7a94df99a7..a879636e8050639f5b3f6f5e1cc6c8431a9f8c86 100644
--- a/services/dynamic/dynamic-json.tester.js
+++ b/services/dynamic/dynamic-json.tester.js
@@ -139,3 +139,13 @@ t.create('JSON from url | request should set Accept header')
   .after(() => {
     expect(headers).to.have.property('accept', 'application/json')
   })
+
+t.create('JSON from url | invalid query')
+  .get(
+    '.json?url=https://github.com/badges/shields/raw/master/package.json&query=$[?'
+  )
+  .expectBadge({
+    label: 'custom badge',
+    message: 'unparseable jsonpath query',
+    color: 'red',
+  })