phacility/phabricator · error · Exception

Curtain extension ("%s", of class "%s") did not return a lis

Error message

Curtain extension ("%s", of class "%s") did not return a list of curtain panels from method "%s". This method must return an array, and each value in the array must be a "%s" object.

What it means

PHUICurtainExtension::buildCurtainPanels($object) must return an array of PHUICurtainPanelView objects — an empty array when the extension has nothing to show. buildExtensionPanels() validates the return value: if the method returns a single panel object, null, or any other non-array, this exception is thrown during page rendering.

Source

Thrown at src/view/extension/PHUICurtainExtension.php:91

        $viewer);

      if (!$has_application) {
        unset($extensions[$key]);
      }
    }

    foreach ($extensions as $key => $extension) {
      if (!$extension->shouldEnableForObject($object)) {
        unset($extensions[$key]);
      }
    }

    $result = array();

    foreach ($extensions as $key => $extension) {
      $panels = $extension->buildCurtainPanels($object);
      if (!is_array($panels)) {
        throw new Exception(
          pht(
            'Curtain extension ("%s", of class "%s") did not return a list of '.
            'curtain panels from method "%s". This method must return an '.
            'array, and each value in the array must be a "%s" object.',
            $key,
            get_class($extension),
            'buildCurtainPanels()',
            'PHUICurtainPanelView'));
      }

      foreach ($panels as $panel_key => $panel) {
        if (!($panel instanceof PHUICurtainPanelView)) {
          throw new Exception(
            pht(
              'Curtain extension ("%s", of class "%s") returned a list of '.
              'curtain panels from "%s" that contains an invalid value: '.
              'a value (with key "%s") is not an object of class "%s". '.
              'Each item in the returned array must be a panel.',

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Wrap single panels in an array: return array($panel);
  2. Make 'return array();' the unconditional last line, and convert guard clauses to return empty arrays.
  3. Keep panel construction in a helper and always return array($this->buildPanel($object)).

Example fix

// before
public function buildCurtainPanels($object) {
  if (!$this->shouldShow($object)) {
    return; // null: throws
  }
  return $this->buildPanel($object); // single object: throws
}

// after
public function buildCurtainPanels($object) {
  if (!$this->shouldShow($object)) {
    return array();
  }
  return array(
    $this->buildPanel($object),
  );
}
Defensive patterns

Strategy: type-guard

Validate before calling

$panels = $extension->buildCurtainPanels($object);
if (!is_array($panels)) {
  // contract violation: fix before rendering in production
  phlog(pht('%s returned a non-array from buildCurtainPanels().', get_class($extension)));
}

Type guard

function returnsPanelArray(PHUICurtainExtension $extension, $object) {
  return is_array($extension->buildCurtainPanels($object));
}

Prevention

When it happens

Trigger: An extension buildCurtainPanels() does 'return $panel;' (single object), 'return;' (null on an early exit), or returns a rendered string or PHUIInfoView instead of an array.

Common situations: A first extension with exactly one panel returned directly; early-return guard clauses added during refactoring; copy-paste from render()-style methods that return views rather than panel lists.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/1f507b645bc7bc81. Report an issue: GitHub.