{"record":{"id":"1f507b645bc7bc81","repo":"phacility/phabricator","slug":"curtain-extension-s-of-class-s-did-not-re-1f507b","errorCode":null,"errorMessage":"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.","messagePattern":"Curtain extension \\(\"(.+?)\", of class \"(.+?)\"\\) did not return a list of curtain panels from method \"(.+?)\"\\. This method must return an array, and each value in the array must be a \"(.+?)\" object\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/view/extension/PHUICurtainExtension.php","lineNumber":91,"sourceCode":"        $viewer);\n\n      if (!$has_application) {\n        unset($extensions[$key]);\n      }\n    }\n\n    foreach ($extensions as $key => $extension) {\n      if (!$extension->shouldEnableForObject($object)) {\n        unset($extensions[$key]);\n      }\n    }\n\n    $result = array();\n\n    foreach ($extensions as $key => $extension) {\n      $panels = $extension->buildCurtainPanels($object);\n      if (!is_array($panels)) {\n        throw new Exception(\n          pht(\n            'Curtain extension (\"%s\", of class \"%s\") did not return a list of '.\n            'curtain panels from method \"%s\". This method must return an '.\n            'array, and each value in the array must be a \"%s\" object.',\n            $key,\n            get_class($extension),\n            'buildCurtainPanels()',\n            'PHUICurtainPanelView'));\n      }\n\n      foreach ($panels as $panel_key => $panel) {\n        if (!($panel instanceof PHUICurtainPanelView)) {\n          throw new Exception(\n            pht(\n              'Curtain extension (\"%s\", of class \"%s\") returned a list of '.\n              'curtain panels from \"%s\" that contains an invalid value: '.\n              'a value (with key \"%s\") is not an object of class \"%s\". '.\n              'Each item in the returned array must be a panel.',","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/view/extension/PHUICurtainExtension.php#L73-L109","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Wrap single panels in an array: return array($panel);","Make 'return array();' the unconditional last line, and convert guard clauses to return empty arrays.","Keep panel construction in a helper and always return array($this->buildPanel($object))."],"exampleFix":"// before\npublic function buildCurtainPanels($object) {\n  if (!$this->shouldShow($object)) {\n    return; // null: throws\n  }\n  return $this->buildPanel($object); // single object: throws\n}\n\n// after\npublic function buildCurtainPanels($object) {\n  if (!$this->shouldShow($object)) {\n    return array();\n  }\n  return array(\n    $this->buildPanel($object),\n  );\n}","handlingStrategy":"type-guard","validationCode":"$panels = $extension->buildCurtainPanels($object);\nif (!is_array($panels)) {\n  // contract violation: fix before rendering in production\n  phlog(pht('%s returned a non-array from buildCurtainPanels().', get_class($extension)));\n}","typeGuard":"function returnsPanelArray(PHUICurtainExtension $extension, $object) {\n  return is_array($extension->buildCurtainPanels($object));\n}","tryCatchPattern":null,"preventionTips":["Make 'return array();' the unconditional last line of buildCurtainPanels().","Guard clauses must 'return array();' too, never a bare 'return;'.","Unit test each extension against a representative object."],"tags":["php","phabricator","curtain-extension","return-type","render"],"backgroundTag":"extension-contract-violation","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}