diff --git a/lib/externallib.php b/lib/externallib.php
index e6d5e99b955..24002e0bc44 100644
--- a/lib/externallib.php
+++ b/lib/externallib.php
@@ -182,7 +182,7 @@ class external_api {
 
         require_once($CFG->libdir . "/pagelib.php");
 
-        $externalfunctioninfo = self::external_function_info($function);
+        $externalfunctioninfo = static::external_function_info($function);
 
         $currentpage = $PAGE;
         $currentcourse = $COURSE;
@@ -252,7 +252,7 @@ class external_api {
 
             $response['error'] = false;
             $response['data'] = $result;
-        } catch (Exception $e) {
+        } catch (Throwable $e) {
             $exception = get_exception_info($e);
             unset($exception->a);
             $exception->backtrace = format_backtrace($exception->backtrace, true);
diff --git a/lib/tests/externallib_test.php b/lib/tests/externallib_test.php
index 619ae286a6c..aa8101f3f4e 100644
--- a/lib/tests/externallib_test.php
+++ b/lib/tests/externallib_test.php
@@ -535,7 +535,7 @@ class core_externallib_testcase extends advanced_testcase {
 
 
     public function test_call_external_function() {
-        global $PAGE, $COURSE;
+        global $PAGE, $COURSE, $CFG;
 
         $this->resetAfterTest(true);
 
@@ -570,6 +570,16 @@ class core_externallib_testcase extends advanced_testcase {
 
         $this->assertSame($beforepage, $PAGE);
         $this->assertSame($beforecourse, $COURSE);
+
+        // Test a function that triggers a PHP exception.
+        require_once($CFG->dirroot . '/lib/tests/fixtures/test_external_function_throwable.php');
+
+        // Call our test function.
+        $result = test_external_function_throwable::call_external_function('core_throw_exception', array(), false);
+
+        $this->assertTrue($result['error']);
+        $this->assertArrayHasKey('exception', $result);
+        $this->assertEquals($result['exception']->message, 'Exception - Modulo by zero');
     }
 
     /**
diff --git a/lib/tests/fixtures/test_external_function_throwable.php b/lib/tests/fixtures/test_external_function_throwable.php
new file mode 100644
index 00000000000..b1e975d73ff
--- /dev/null
+++ b/lib/tests/fixtures/test_external_function_throwable.php
@@ -0,0 +1,86 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * An external function that throws an exception, for tests.
+ *
+ * @package    core
+ * @category   phpunit
+ * @copyright  2020 Dani Palou
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once("$CFG->libdir/externallib.php");
+
+/**
+ * Create an external function that throws an exception, for tests.
+ *
+ * @copyright  2020 Dani Palou
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class test_external_function_throwable extends external_api {
+
+    /**
+     * Returns description of throw_exception() parameters.
+     *
+     * @return external_function_parameters
+     */
+    public static function throw_exception_parameters() {
+        return new external_function_parameters(array());
+    }
+
+    /**
+     * Throws a PHP error.
+     *
+     * @return array empty array.
+     */
+    public static function throw_exception() {
+        $a = 1 % 0;
+
+        return array();
+    }
+
+    /**
+     * Returns description of throw_exception() result value.
+     *
+     * @return external_description
+     */
+    public static function throw_exception_returns() {
+        return new external_single_structure(array());
+    }
+
+    /**
+     * Override external_function_info to accept our fake WebService.
+     */
+    public static function external_function_info($function, $strictness=MUST_EXIST) {
+        if ($function == 'core_throw_exception') {
+            // Convert it to an object.
+            $function = new stdClass();
+            $function->name = $function;
+            $function->classname = 'test_external_function_throwable';
+            $function->methodname = 'throw_exception';
+            $function->classpath = ''; // No need to define class path because current file is already loaded.
+            $function->component = 'fake';
+            $function->capabilities = '';
+            $function->services = 'moodle_mobile_app';
+            $function->loginrequired = false;
+        }
+
+        return parent::external_function_info($function, $strictness);
+    }
+}