Page MenuHomePhabricator

Calendar: Call to a member function format() on null at $this->getQueryDateFrom($query)->getDateTime()
Closed, ResolvedPublicBUG REPORT

Description

Upstream: https://we.phorge.it/T15943

Two appearances in total (Aug11 and Aug17) so far:

[2024-08-17 22:11:24] EXCEPTION: (Error) Call to a member function format() on null at [<phorge>/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php:419]
arcanist(), ava(), phorge(), translations(), wmf-ext-misc()
  #0 phlog(Error) called at [<phorge>/src/aphront/handler/PhabricatorDefaultRequestExceptionHandler.php:41]
  #1 PhabricatorDefaultRequestExceptionHandler::handleRequestThrowable(AphrontRequest, Error) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:751]
  #2 AphrontApplicationConfiguration::handleThrowable(Error) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:296]
  #3 AphrontApplicationConfiguration::processRequest(AphrontRequest, PhutilDeferredLog, AphrontPHPHTTPSink, MultimeterControl) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:204]
  #4 AphrontApplicationConfiguration::runHTTPRequest(AphrontPHPHTTPSink) called at [<phorge>/webroot/index.php:35]

Event Timeline

I do not manage to reproduce no matter which language settings I choose, but an easy reproducer is replacing
'd' => "{$start_year}-{$start_month}-{$start_day}"
in https://we.phorge.it/source/phorge/browse/master/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php$539 with a bogus value like
'd' => "2024-0A-696"

PhabricatorCalendarEventSearchEngine::buildCalendarMonthView has the line $from = $this->getQueryDateFrom($query)->getDateTime();.
AphrontFormDateControlValue::getDateTime() calls AphrontFormDateControlValue::newDateTime(). Here, $datetime = new DateTime("{$date} {$time}", $zone); fails for unknown reasons, so the methods returns null when catching an exception.

Note that the three existing if (!$datetime) checks in https://we.phorge.it/source/phorge/browse/master/src/view/form/control/AphrontFormDateControlValue.php imply that this can be null.

There are two options to deal with this:

One is to continue ignore that DateTime should not be null, as catch (Exception $ex) { return null; } code in AphrontFormDateControlValue already does, and introduce some fallback code in PhabricatorCalendarEventSearchEngine to handle it being null:

     $from = $this->getQueryDateFrom($query)->getDateTime();
+    if (!$from) {
+    // Hide exception and render current month everywhere, no matter what
+      $from = $this->getSafeDate($from)->getDateTime(); //
+    }

Other option is to stop ignoring exceptions in AphrontFormDateControlValue and throw them instead:

       $datetime->setTimezone($zone);
+    } catch (DateMalformedStringException $ex) { // PHP >= 8.3.0
+      throw new DateMalformedStringException($ex->getMessage());
     } catch (Exception $ex) {
-      return null;
+      throw new Exception($ex->getMessage());
     }
     return $datetime;
Aklapper triaged this task as Low priority.
Aklapper edited projects, added Phabricator (Upstream), Upstream; removed Phabricator.

Boy oh boy... After reading this piece of code to understand it better, I realize how easy this is to trigger:
Check "Occurs After" in the advanced search in calendar month view on http://phorge.localhost/calendar/query/advanced/ , enter an invalid date or time abcde, click Search. Same applies for buildCalendarDayView() in the line $month_uri = $browse_uri.$from->format('Y/m/');
I'll cook up an upstream patch to validate values and throw an exception.

This issue should now be fixed on phabricator.wikimedia.org after today's software deployment in T404134.