From 266d0433966e299614c5127b21ec85a88510f4e8 Mon Sep 17 00:00:00 2001 From: Spencer Kittleson Date: Fri, 28 Aug 2026 23:46:55 -0700 Subject: [PATCH] Coerce non-string API error bodies to string in ApiResult::getError() getError() is declared ": ?string" but could return non-string scalars (bool/int/float) deserialized straight out of the API response body, which throws a TypeError under strict_types instead of returning a value. This TypeError is not an Exception, so it isn't caught by the try/catch blocks that construct ApiResultException, turning a handled API error into an uncaught fatal for the current request. Coerce every returned value with StringEx::stringify() so getError() always honors its declared ?string contract regardless of what shape the API serialized. Deki issue: https://github.com/MindTouch/Deki/issues/38741 --- src/ApiResult.php | 6 +++--- tests/ApiResult/getError_Test.php | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/ApiResult.php b/src/ApiResult.php index 4a5e274..0360017 100644 --- a/src/ApiResult.php +++ b/src/ApiResult.php @@ -36,13 +36,13 @@ public function getError() : ?string { // formatted API error $error = $this->getVal('body/error/message'); if($error !== null) { - return $error; + return StringEx::stringify($error); } // exception API error $error = $this->getVal('body/exception/message'); if($error !== null) { - return $error; + return StringEx::stringify($error); } // curl error @@ -57,7 +57,7 @@ public function getError() : ?string { if(is_array($error)) { return $this->getXml('body'); } - return $error; + return StringEx::stringify($error); } return null; } diff --git a/tests/ApiResult/getError_Test.php b/tests/ApiResult/getError_Test.php index 6feaa29..32bd30b 100644 --- a/tests/ApiResult/getError_Test.php +++ b/tests/ApiResult/getError_Test.php @@ -28,7 +28,14 @@ public static function body_expected_dataProvider() : array { [['error' => ['message' => 'foo']], 'foo'], [['exception' => ['message' => 'bar']], 'bar'], [['foo' => ['qux' => ['@id' => '123']]], ''], - ['qux', 'qux'] + ['qux', 'qux'], + + // non-string scalars deserialized from the API response body must be coerced to + // string, not returned as-is: getError() is declared ": ?string" and under + // strict_types this throws a TypeError instead of returning a value + [['error' => ['message' => true]], '1'], + [['exception' => ['message' => 42]], '42'], + [3.14, '3.14'] ]; } @@ -36,7 +43,7 @@ public static function body_expected_dataProvider() : array { * @dataProvider body_expected_dataProvider * @test */ - public function Can_get_error_from_body(string|array $body, string $expected) { + public function Can_get_error_from_body(string|array|bool|int|float $body, string $expected) { // arrange $data = [