phacility/phabricator · error · Exception

Call %s before rendering tokenizers. Use %s on %s to do this

Error message

Call %s before rendering tokenizers. Use %s on %s to do this easily.

What it means

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.

Source

Thrown at src/view/form/control/AphrontFormTokenizerControl.php:130

          $tokens,
          'getAvailabilityColor',
          'getKey'),
        'limit' => $this->limit,
        'username' => $username,
        'placeholder' => $placeholder,
        'browseURI' => $browse_uri,
        'disabled' => $this->getDisabled(),
      ));
    }

    return $template->render();
  }

  private function loadHandles() {
    if ($this->handles === null) {
      $viewer = $this->getUser();
      if (!$viewer) {
        throw new Exception(
          pht(
            'Call %s before rendering tokenizers. '.
            'Use %s on %s to do this easily.',
            'setUser()',
            'appendControl()',
            'AphrontFormView'));
      }

      $values = nonempty($this->getValue(), array());

      $phids = array();
      foreach ($values as $value) {
        if (!PhabricatorTypeaheadDatasource::isFunctionToken($value)) {
          $phids[] = $value;
        }
      }

      $this->handles = $viewer->loadHandles($phids);

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Add the control with $form->appendControl($control) so the form propagates its viewer to it.
  2. Or set the user explicitly on the control: $control->setUser($viewer) (setViewer() is the non-deprecated equivalent).
  3. Confirm the parent form itself had setUser() called; otherwise fix that too.

Example fix

// before
$form = id(new AphrontFormView())
  ->setUser($viewer);
$tokenizer = id(new AphrontFormTokenizerControl())
  ->setDatasource(new PhabricatorProjectDatasource());
$form->appendChild($tokenizer); // not registered as a control: no viewer wired

// after
$form = id(new AphrontFormView())
  ->setUser($viewer);
$tokenizer = id(new AphrontFormTokenizerControl())
  ->setDatasource(new PhabricatorProjectDatasource());
$form->appendControl($tokenizer); // form wires viewer in at render time
Defensive patterns

Strategy: validation

Validate before calling

if (!$control->hasViewer()) {
  $control->setUser($viewer);
}
$form->appendControl($control);

Prevention

When it happens

Trigger: $form->appendChild($tokenizer) instead of $form->appendControl($tokenizer); or instantiating an AphrontFormTokenizerControl and rendering it outside a form without setUser($viewer).

Common situations: 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).

Related errors


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