{"record":{"id":"167d9cbc36af9148","repo":"phacility/phabricator","slug":"call-s-before-rendering-tokenizers-use-s-on-s","errorCode":null,"errorMessage":"Call %s before rendering tokenizers. Use %s on %s to do this easily.","messagePattern":"Call (.+?) before rendering tokenizers\\. Use (.+?) on (.+?) to do this easily\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/view/form/control/AphrontFormTokenizerControl.php","lineNumber":130,"sourceCode":"          $tokens,\n          'getAvailabilityColor',\n          'getKey'),\n        'limit' => $this->limit,\n        'username' => $username,\n        'placeholder' => $placeholder,\n        'browseURI' => $browse_uri,\n        'disabled' => $this->getDisabled(),\n      ));\n    }\n\n    return $template->render();\n  }\n\n  private function loadHandles() {\n    if ($this->handles === null) {\n      $viewer = $this->getUser();\n      if (!$viewer) {\n        throw new Exception(\n          pht(\n            'Call %s before rendering tokenizers. '.\n            'Use %s on %s to do this easily.',\n            'setUser()',\n            'appendControl()',\n            'AphrontFormView'));\n      }\n\n      $values = nonempty($this->getValue(), array());\n\n      $phids = array();\n      foreach ($values as $value) {\n        if (!PhabricatorTypeaheadDatasource::isFunctionToken($value)) {\n          $phids[] = $value;\n        }\n      }\n\n      $this->handles = $viewer->loadHandles($phids);","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/view/form/control/AphrontFormTokenizerControl.php#L112-L148","documentation":"To display existing values as tokens, the tokenizer must resolve PHIDs to handles, which requires a viewer (loadHandles() calls getUser()). The form wires its viewer into controls only at render time and only for controls registered via appendControl() (buildLayoutView() calls setViewer() on $this->controls). A tokenizer added with appendChild(), or rendered standalone, never receives a viewer and throws this exception. The message names the two fixes: setUser() on the control, or appendControl() on AphrontFormView.","triggerScenarios":"$form->appendChild($tokenizer) instead of $form->appendControl($tokenizer); or instantiating an AphrontFormTokenizerControl and rendering it outside a form without setUser($viewer).","commonSituations":"Using generic appendChild() out of habit when adding controls; embedding a tokenizer in a custom (non-AphrontFormView) container; forms whose own viewer was also never set (which surfaces the AphrontFormView render error first or alongside).","solutions":["Add the control with $form->appendControl($control) so the form propagates its viewer to it.","Or set the user explicitly on the control: $control->setUser($viewer) (setViewer() is the non-deprecated equivalent).","Confirm the parent form itself had setUser() called; otherwise fix that too."],"exampleFix":"// before\n$form = id(new AphrontFormView())\n  ->setUser($viewer);\n$tokenizer = id(new AphrontFormTokenizerControl())\n  ->setDatasource(new PhabricatorProjectDatasource());\n$form->appendChild($tokenizer); // not registered as a control: no viewer wired\n\n// after\n$form = id(new AphrontFormView())\n  ->setUser($viewer);\n$tokenizer = id(new AphrontFormTokenizerControl())\n  ->setDatasource(new PhabricatorProjectDatasource());\n$form->appendControl($tokenizer); // form wires viewer in at render time","handlingStrategy":"validation","validationCode":"if (!$control->hasViewer()) {\n  $control->setUser($viewer);\n}\n$form->appendControl($control);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always add form controls through appendControl(), never appendChild().","hasViewer() is public on every AphrontView — assert it for tokenizer/typeahead controls before render.","Standalone tokenizers need setUser($viewer) before any render or willRender() pass."],"tags":["php","phabricator","tokenizer","handles","viewer"],"backgroundTag":"missing-viewer-context","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}