phacility/phabricator · error · Exception
You must set a datasource to use a TokenizerControl.
Error message
You must set a datasource to use a TokenizerControl.
What it means
An AphrontFormTokenizerControl renders a typeahead tokenizer whose suggestion source, token rendering, and placeholder text all come from a PhabricatorTypeaheadDatasource. renderInput() throws when no datasource was set via setDatasource(), because there is no default source of suggestions to fall back to.
Source
Thrown at src/view/form/control/AphrontFormTokenizerControl.php:65
// render them.
$this->loadHandles();
}
protected function renderInput() {
$name = $this->getName();
$handles = $this->loadHandles();
$handles = iterator_to_array($handles);
if ($this->getID()) {
$id = $this->getID();
} else {
$id = celerity_generate_unique_node_id();
}
$datasource = $this->datasource;
if (!$datasource) {
throw new Exception(
pht('You must set a datasource to use a TokenizerControl.'));
}
$datasource->setViewer($this->getUser());
$placeholder = $this->placeholder;
if ($placeholder === null || !strlen($placeholder)) {
$placeholder = $datasource->getPlaceholderText();
}
$values = nonempty($this->getValue(), array());
$tokens = $datasource->renderTokens($values);
foreach ($tokens as $token) {
$token->setInputName($this->getName());
}
$template = id(new AphrontTokenizerTemplateView())
->setName($name)View on GitHub (pinned to 5720a38cfe)
Solutions
- Call setDatasource() with a concrete PhabricatorTypeaheadDatasource, e.g. ->setDatasource(new PhabricatorPeopleDatasource()) or new PhabricatorProjectDatasource().
- Check any conditional branches that build the control and ensure every path sets the datasource.
- If you only need a fixed option list, use AphrontFormSelectControl instead of a tokenizer.
Example fix
// before
$control = id(new AphrontFormTokenizerControl())
->setLabel(pht('Reviewers'))
->setName('reviewers')
->setValue($phids);
// no datasource: renderInput() throws
// after
$control = id(new AphrontFormTokenizerControl())
->setLabel(pht('Reviewers'))
->setName('reviewers')
->setValue($phids)
->setDatasource(new PhabricatorPeopleDatasource()); Defensive patterns
Strategy: validation
Validate before calling
// There is no public getDatasource(); guarantee it at construction time:
function newTokenizerControl($name, PhabricatorTypeaheadDatasource $datasource) {
return id(new AphrontFormTokenizerControl())
->setName($name)
->setDatasource($datasource);
} Prevention
- Treat setDatasource() as a mandatory constructor argument: build tokenizers only through a helper that typehints the datasource.
- A tokenizer without a datasource can never render.
- Use AphrontFormSelectControl for fixed option lists instead.
When it happens
Trigger: Creating an AphrontFormTokenizerControl and setting name/label/value but never calling setDatasource(new SomeDatasource()) before the form renders.
Common situations: Copy-pasting a tokenizer from another form and losing the datasource line; conditionally setting the datasource in a branch that is skipped; quickly prototyping a custom form.
Related errors
- Unable to parse function and arguments for token "%s".
- Custom field class "%s" does not exist.
- Custom field class "%s" does not implement interface "%s".
- No custom field role specified.
- No custom field key specified.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/12f503591f7a280b.
Report an issue: GitHub.