diff --git a/src/aphront/configuration/AphrontApplicationConfiguration.php b/src/aphront/configuration/AphrontApplicationConfiguration.php index a479209125..c24d59ac90 100644 --- a/src/aphront/configuration/AphrontApplicationConfiguration.php +++ b/src/aphront/configuration/AphrontApplicationConfiguration.php @@ -312,11 +312,17 @@ final class AphrontApplicationConfiguration if ($response_exception) { // If we encountered an exception while building a normal response, then // encountered another exception while building a response for the first - // exception, just throw the original exception. It is more likely to be - // useful and point at a root cause than the second exception we ran into - // while telling the user about it. + // exception, throw an aggregate exception that will be unpacked by the + // higher-level handler. This is above our pay grade. if ($original_exception) { - throw $original_exception; + throw new PhutilAggregateException( + pht( + 'Encountered a processing exception, then another exception when '. + 'trying to build a response for the first exception.'), + array( + $response_exception, + $original_exception, + )); } // If we built a response successfully and then ran into an exception diff --git a/src/aphront/response/AphrontUnhandledExceptionResponse.php b/src/aphront/response/AphrontUnhandledExceptionResponse.php index 32d612ca50..2c605cf150 100644 --- a/src/aphront/response/AphrontUnhandledExceptionResponse.php +++ b/src/aphront/response/AphrontUnhandledExceptionResponse.php @@ -61,9 +61,39 @@ final class AphrontUnhandledExceptionResponse return 'unhandled-exception'; } - protected function getResponseBody() { - $ex = $this->exception; + private function getExceptionList() { + return $this->expandException($this->exception); + } + private function expandException($root) { + if ($root instanceof PhutilAggregateException) { + $list = array(); + + $list[] = $root; + + foreach ($root->getExceptions() as $ex) { + foreach ($this->expandException($ex) as $child) { + $list[] = $child; + } + } + + return $list; + } + + return array($root); + } + + protected function getResponseBody() { + $body = array(); + + foreach ($this->getExceptionList() as $ex) { + $body[] = $this->newHTMLMessage($ex); + } + + return $body; + } + + private function newHTMLMessage($ex) { if ($ex instanceof AphrontMalformedRequestException) { $title = $ex->getTitle(); } else { @@ -122,12 +152,20 @@ final class AphrontUnhandledExceptionResponse } protected function buildPlainTextResponseString() { - $ex = $this->exception; + $messages = array(); + foreach ($this->getExceptionList() as $exception) { + $messages[] = $this->newPlainTextMessage($exception); + } + + return implode("\n\n", $messages); + } + + private function newPlainTextMessage($exception) { return pht( '%s: %s', - get_class($ex), - $ex->getMessage()); + get_class($exception), + $exception->getMessage()); } }