phacility/phabricator · error · Exception

No such variable '%s'!

Error message

No such variable '%s'!

What it means

HarbormasterBuildStepImplementation::mergeVariables() scans a pattern for ${name} placeholders and requires every name to be present in the variables dict before substituting values (it replaces placeholders with %s and calls $function, e.g. vsprintf). An unknown placeholder throws so the sprintf-style call can never receive a mismatched argument list or silently produce broken output.

Source

Thrown at src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php:204

   * ...into a string with variables merged into it safely:
   *
   *   ls 'dir with spaces'
   *
   * @param string Name of a `vxsprintf` function, like @{function:vcsprintf}.
   * @param string User-provided pattern string containing `${variables}`.
   * @param dict   List of available replacement variables.
   * @return string String with variables replaced safely into it.
   */
  protected function mergeVariables($function, $pattern, array $variables) {
    $regexp = '@\\$\\{(?P<name>[a-z\\./_-]+)\\}@';

    $matches = null;
    preg_match_all($regexp, $pattern, $matches);

    $argv = array();
    foreach ($matches['name'] as $name) {
      if (!array_key_exists($name, $variables)) {
        throw new Exception(pht("No such variable '%s'!", $name));
      }
      $argv[] = $variables[$name];
    }

    $pattern = str_replace('%', '%%', $pattern);
    $pattern = preg_replace($regexp, '%s', $pattern);

    return call_user_func($function, $pattern, $argv);
  }

  public function getFieldSpecifications() {
    return array();
  }

  protected function formatSettingForDescription($key, $default = null) {
    return $this->formatValueForDescription($this->getSetting($key, $default));
  }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Correct the pattern so it only references variables that exist in the variables array (e.g. ${revision} not ${buildable.revision})
  2. Extend the variables array passed to mergeVariables to include the missing key
  3. Before editing templates, list the variables the implementation actually provides (shown in the plan editor help) and keep edits consistent with them

Example fix

// before
$pattern = 'make ${buildable.revision}'; // 'buildable.revision' not in $variables
$this->mergeVariables('vsprintf', $pattern, $variables);
// after
$pattern = 'make ${revision}';
$this->mergeVariables('vsprintf', $pattern, $variables);
Defensive patterns

Strategy: validation

Validate before calling

preg_match_all('/[$][{]([a-z./_-]+)[}]/', $pattern, $m);
foreach ($m[1] as $name) {
  if (!array_key_exists($name, $variables)) {
    // fix the pattern or add the variable before calling mergeVariables
  }
}

Prevention

When it happens

Trigger: A command or field pattern containing ${buildable.revision} while the variables array passed to mergeVariables only provides other keys; renaming a variable key while old step configurations still reference the old name.

Common situations: Editing a build plan template to reference a variable the current build context does not provide; Phabricator upgrades that change available variable names; copying a step configuration between plans with different variable sets.

Related errors


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