We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Catch ValueError during network discovery for when JSON parsing fails
<!--
Instructions:
 * Fill out the sections below, replace …'s with information about your issue
 * Use the 'preview' function above this text box to verify formatting before submitting
-->

### Observed behavior
<!--
Description of the behavior that was observed, including screenshots or other references when applicable
-->

When trying to import content channels (from local network or internet), no error message is produced even though the connection isn't established. (The "trying to connect" message stays on forever) This happens when there is a typo in the address. (I used kolibri-demo.learningequality.omg)  When there's no internet, an error message DOES get produced. 

### Expected behavior
<!--
Description of what behavior was expected but did not occur
-->

An error message should've been produced.

### User-facing consequences
<!--
Implications and real-world consequences for learners, coaches, admins, and other users of the application
-->

The user will not know how long they have to wait to see if the connection is being established.

### Errors and logs
<!--
Relevant logs from:
 * the command line
 * ~/.kolibri/logs/kolibri.txt
 * the browser console

Please wrap errors in triple backticks for clean formatting like this:
```
01:10 info: something happened
01:12 error: something bad happened
```
-->

…

### Steps to reproduce
<!--
Precise steps that someone else can follow in order to see this behavior
-->

Import content channels from local network or internet >input "kolibri-demo.learningequality.omg" or something else with a typo in it.

### Context
<!--
Tell us about your environment, including:
 * Kolibri version
 * Operating system
 * Browser
-->

Kolibri version: 0.14.3
Operating system: Android 5.1
Browser: Android App
Device: BLU Advance 5.0


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kolibri/core/discovery/utils/network/client.py`
Content:
```
1 import logging
2 
3 import requests
4 from six.moves.urllib.parse import urljoin
5 
6 from . import errors
7 from .urls import get_normalized_url_variations
8 
9 logger = logging.getLogger(__name__)
10 
11 
12 class NetworkClient(object):
13     DEFAULT_TIMEOUT_IN_SECS = 5
14 
15     def __init__(self, base_url=None, address=None, timeout=None, **kwargs):
16         """If an explicit base_url is already known, provide that. If a vague address is provided, we can try to infer the base_url"""
17         if not base_url and not address:
18             raise Exception(
19                 "You must provide either a `base_url` or `address` argument"
20             )
21         self.timeout = timeout or self.DEFAULT_TIMEOUT_IN_SECS
22         self.session = requests.Session(**kwargs)
23         if base_url:
24             self.base_url = self._attempt_connections([base_url])
25         else:
26             # normalize the URL and try a number of variations until we find one that's able to connect
27             logger.info(
28                 "Attempting connections to variations of the URL: {}".format(address)
29             )
30             self.base_url = self._attempt_connections(
31                 get_normalized_url_variations(address)
32             )
33 
34     def _attempt_connections(self, urls):
35         # try each of the URLs in turn, returning the first one that succeeds
36         for url in urls:
37             try:
38                 logger.info("Attempting connection to: {}".format(url))
39                 response = self.get(
40                     "/api/public/info/",
41                     base_url=url,
42                     timeout=self.timeout,
43                     allow_redirects=True,
44                 )
45                 # check that we successfully connected, and if we were redirected that it's still the right endpoint
46                 if response.status_code == 200 and response.url.rstrip("/").endswith(
47                     "/api/public/info"
48                 ):
49                     self.info = response.json()
50                     if self.info["application"] not in ["studio", "kolibri"]:
51                         raise requests.RequestException(
52                             "Server is not running Kolibri or Studio"
53                         )
54                     logger.info("Success! We connected to: {}".format(response.url))
55                     return response.url.rstrip("/").replace("api/public/info", "")
56             except (requests.RequestException) as e:
57                 logger.info("Unable to connect: {}".format(e))
58 
59         # we weren't able to connect to any of the URL variations, so all we can do is throw
60         raise errors.NetworkLocationNotFound()
61 
62     def get(self, path, **kwargs):
63         return self.request("get", path, **kwargs)
64 
65     def head(self, path, **kwargs):
66         return self.request("head", path, **kwargs)
67 
68     def request(self, method, path, base_url=None, **kwargs):
69         base_url = base_url or self.base_url
70         url = urljoin(base_url, path)
71         response = getattr(self.session, method)(url, **kwargs)
72         response.raise_for_status()
73         return response
74
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kolibri/core/discovery/utils/network/client.py b/kolibri/core/discovery/utils/network/client.py
--- a/kolibri/core/discovery/utils/network/client.py
+++ b/kolibri/core/discovery/utils/network/client.py
@@ -55,6 +55,10 @@
                     return response.url.rstrip("/").replace("api/public/info", "")
             except (requests.RequestException) as e:
                 logger.info("Unable to connect: {}".format(e))
+            except ValueError:
+                logger.info(
+                    "Invalid JSON returned when attempting to connect to a remote server"
+                )
 
         # we weren't able to connect to any of the URL variations, so all we can do is throw
         raise errors.NetworkLocationNotFound()

{"golden_diff": "diff --git a/kolibri/core/discovery/utils/network/client.py b/kolibri/core/discovery/utils/network/client.py\n--- a/kolibri/core/discovery/utils/network/client.py\n+++ b/kolibri/core/discovery/utils/network/client.py\n@@ -55,6 +55,10 @@\n                     return response.url.rstrip(\"/\").replace(\"api/public/info\", \"\")\n             except (requests.RequestException) as e:\n                 logger.info(\"Unable to connect: {}\".format(e))\n+            except ValueError:\n+                logger.info(\n+                    \"Invalid JSON returned when attempting to connect to a remote server\"\n+                )\n \n         # we weren't able to connect to any of the URL variations, so all we can do is throw\n         raise errors.NetworkLocationNotFound()\n", "issue": "Catch ValueError during network discovery for when JSON parsing fails\n<!--\r\nInstructions:\r\n * Fill out the sections below, replace \u2026's with information about your issue\r\n * Use the 'preview' function above this text box to verify formatting before submitting\r\n-->\r\n\r\n### Observed behavior\r\n<!--\r\nDescription of the behavior that was observed, including screenshots or other references when applicable\r\n-->\r\n\r\nWhen trying to import content channels (from local network or internet), no error message is produced even though the connection isn't established. (The \"trying to connect\" message stays on forever) This happens when there is a typo in the address. (I used kolibri-demo.learningequality.omg)  When there's no internet, an error message DOES get produced. \r\n\r\n### Expected behavior\r\n<!--\r\nDescription of what behavior was expected but did not occur\r\n-->\r\n\r\nAn error message should've been produced.\r\n\r\n### User-facing consequences\r\n<!--\r\nImplications and real-world consequences for learners, coaches, admins, and other users of the application\r\n-->\r\n\r\nThe user will not know how long they have to wait to see if the connection is being established.\r\n\r\n### Errors and logs\r\n<!--\r\nRelevant logs from:\r\n * the command line\r\n * ~/.kolibri/logs/kolibri.txt\r\n * the browser console\r\n\r\nPlease wrap errors in triple backticks for clean formatting like this:\r\n```\r\n01:10 info: something happened\r\n01:12 error: something bad happened\r\n```\r\n-->\r\n\r\n\u2026\r\n\r\n### Steps to reproduce\r\n<!--\r\nPrecise steps that someone else can follow in order to see this behavior\r\n-->\r\n\r\nImport content channels from local network or internet >input \"kolibri-demo.learningequality.omg\" or something else with a typo in it.\r\n\r\n### Context\r\n<!--\r\nTell us about your environment, including:\r\n * Kolibri version\r\n * Operating system\r\n * Browser\r\n-->\r\n\r\nKolibri version: 0.14.3\r\nOperating system: Android 5.1\r\nBrowser: Android App\r\nDevice: BLU Advance 5.0\r\n\n", "before_files": [{"content": "import logging\n\nimport requests\nfrom six.moves.urllib.parse import urljoin\n\nfrom . import errors\nfrom .urls import get_normalized_url_variations\n\nlogger = logging.getLogger(__name__)\n\n\nclass NetworkClient(object):\n    DEFAULT_TIMEOUT_IN_SECS = 5\n\n    def __init__(self, base_url=None, address=None, timeout=None, **kwargs):\n        \"\"\"If an explicit base_url is already known, provide that. If a vague address is provided, we can try to infer the base_url\"\"\"\n        if not base_url and not address:\n            raise Exception(\n                \"You must provide either a `base_url` or `address` argument\"\n            )\n        self.timeout = timeout or self.DEFAULT_TIMEOUT_IN_SECS\n        self.session = requests.Session(**kwargs)\n        if base_url:\n            self.base_url = self._attempt_connections([base_url])\n        else:\n            # normalize the URL and try a number of variations until we find one that's able to connect\n            logger.info(\n                \"Attempting connections to variations of the URL: {}\".format(address)\n            )\n            self.base_url = self._attempt_connections(\n                get_normalized_url_variations(address)\n            )\n\n    def _attempt_connections(self, urls):\n        # try each of the URLs in turn, returning the first one that succeeds\n        for url in urls:\n            try:\n                logger.info(\"Attempting connection to: {}\".format(url))\n                response = self.get(\n                    \"/api/public/info/\",\n                    base_url=url,\n                    timeout=self.timeout,\n                    allow_redirects=True,\n                )\n                # check that we successfully connected, and if we were redirected that it's still the right endpoint\n                if response.status_code == 200 and response.url.rstrip(\"/\").endswith(\n                    \"/api/public/info\"\n                ):\n                    self.info = response.json()\n                    if self.info[\"application\"] not in [\"studio\", \"kolibri\"]:\n                        raise requests.RequestException(\n                            \"Server is not running Kolibri or Studio\"\n                        )\n                    logger.info(\"Success! We connected to: {}\".format(response.url))\n                    return response.url.rstrip(\"/\").replace(\"api/public/info\", \"\")\n            except (requests.RequestException) as e:\n                logger.info(\"Unable to connect: {}\".format(e))\n\n        # we weren't able to connect to any of the URL variations, so all we can do is throw\n        raise errors.NetworkLocationNotFound()\n\n    def get(self, path, **kwargs):\n        return self.request(\"get\", path, **kwargs)\n\n    def head(self, path, **kwargs):\n        return self.request(\"head\", path, **kwargs)\n\n    def request(self, method, path, base_url=None, **kwargs):\n        base_url = base_url or self.base_url\n        url = urljoin(base_url, path)\n        response = getattr(self.session, method)(url, **kwargs)\n        response.raise_for_status()\n        return response\n", "path": "kolibri/core/discovery/utils/network/client.py"}], "after_files": [{"content": "import logging\n\nimport requests\nfrom six.moves.urllib.parse import urljoin\n\nfrom . import errors\nfrom .urls import get_normalized_url_variations\n\nlogger = logging.getLogger(__name__)\n\n\nclass NetworkClient(object):\n    DEFAULT_TIMEOUT_IN_SECS = 5\n\n    def __init__(self, base_url=None, address=None, timeout=None, **kwargs):\n        \"\"\"If an explicit base_url is already known, provide that. If a vague address is provided, we can try to infer the base_url\"\"\"\n        if not base_url and not address:\n            raise Exception(\n                \"You must provide either a `base_url` or `address` argument\"\n            )\n        self.timeout = timeout or self.DEFAULT_TIMEOUT_IN_SECS\n        self.session = requests.Session(**kwargs)\n        if base_url:\n            self.base_url = self._attempt_connections([base_url])\n        else:\n            # normalize the URL and try a number of variations until we find one that's able to connect\n            logger.info(\n                \"Attempting connections to variations of the URL: {}\".format(address)\n            )\n            self.base_url = self._attempt_connections(\n                get_normalized_url_variations(address)\n            )\n\n    def _attempt_connections(self, urls):\n        # try each of the URLs in turn, returning the first one that succeeds\n        for url in urls:\n            try:\n                logger.info(\"Attempting connection to: {}\".format(url))\n                response = self.get(\n                    \"/api/public/info/\",\n                    base_url=url,\n                    timeout=self.timeout,\n                    allow_redirects=True,\n                )\n                # check that we successfully connected, and if we were redirected that it's still the right endpoint\n                if response.status_code == 200 and response.url.rstrip(\"/\").endswith(\n                    \"/api/public/info\"\n                ):\n                    self.info = response.json()\n                    if self.info[\"application\"] not in [\"studio\", \"kolibri\"]:\n                        raise requests.RequestException(\n                            \"Server is not running Kolibri or Studio\"\n                        )\n                    logger.info(\"Success! We connected to: {}\".format(response.url))\n                    return response.url.rstrip(\"/\").replace(\"api/public/info\", \"\")\n            except (requests.RequestException) as e:\n                logger.info(\"Unable to connect: {}\".format(e))\n            except ValueError:\n                logger.info(\n                    \"Invalid JSON returned when attempting to connect to a remote server\"\n                )\n\n        # we weren't able to connect to any of the URL variations, so all we can do is throw\n        raise errors.NetworkLocationNotFound()\n\n    def get(self, path, **kwargs):\n        return self.request(\"get\", path, **kwargs)\n\n    def head(self, path, **kwargs):\n        return self.request(\"head\", path, **kwargs)\n\n    def request(self, method, path, base_url=None, **kwargs):\n        base_url = base_url or self.base_url\n        url = urljoin(base_url, path)\n        response = getattr(self.session, method)(url, **kwargs)\n        response.raise_for_status()\n        return response\n", "path": "kolibri/core/discovery/utils/network/client.py"}]}