phacility/phabricator · error · Exception

Template "%s" is not a valid template.

Error message

Template "%s" is not a valid template.

What it means

PhabricatorMemeEngine::newAsset() renders a meme by first loading the template image via loadTemplateFile(); when that returns nothing (no macro/template file for the configured template name) it throws this exception. Note the interpolation passes the falsy $template, so the message renders as 'Template "" is not a valid template.' -- the useful information is which template name was set on the engine, not the interpolated value.

Source

Thrown at src/applications/macro/engine/PhabricatorMemeEngine.php:67

  public function getGenerateURI() {
    $params = array(
      'macro' => $this->getTemplate(),
      'above' => $this->getAboveText(),
      'below' => $this->getBelowText(),
    );

    return new PhutilURI('/macro/meme/', $params);
  }

  public function newAsset() {
    $cache = $this->loadCachedFile();
    if ($cache) {
      return $cache;
    }

    $template = $this->loadTemplateFile();
    if (!$template) {
      throw new Exception(
        pht(
          'Template "%s" is not a valid template.',
          $template));
    }

    $hash = $this->newTransformHash();

    $asset = $this->newAssetFile($template);

    $xfile = id(new PhabricatorTransformedFile())
      ->setOriginalPHID($template->getPHID())
      ->setTransformedPHID($asset->getPHID())
      ->setTransform($hash);

    try {
      $caught = null;

      $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Open the Macro application and confirm a macro exists for the template name; use its exact name.
  2. Re-upload the missing template macro if it was deleted.
  3. If you control the call site, verify the template resolves before invoking newAsset() (see exampleFix).

Example fix

// before
$engine = id(new PhabricatorMemeEngine())
  ->setTemplateByName('nonexistent_template')
  ->setTopText('hi');
$asset = $engine->newAsset(); // throws
// after
$engine = id(new PhabricatorMemeEngine())
  ->setTemplateByName($valid_macro_name)
  ->setTopText('hi');
$asset = $engine->newAsset();
// guard before rendering when template comes from user input:
if (!$macro) {
  return $this->newDialog()->setTitle(pht('Unknown Template'));
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify the template resolves before rendering a meme:
$template = $engine->loadTemplateFile();
if (!$template) {
  return new Aphront404Response(); // or render 'unknown template' dialog
}
$asset = $engine->newAsset();

Type guard

function memeTemplateExists($template_name) {
  $macro = id(new PhabricatorFileQuery())
    ->setViewer(PhabricatorUser::getOmnipotentUser())
    ->withNames(array($template_name))
    ->executeOne();
  return (bool)$macro;
}

Try / catch

try {
  $asset = $engine->newAsset();
} catch (Exception $ex) {
  // template macro missing (deleted or never uploaded); degrade gracefully
  return $this->newDialog()->setTitle(pht('Unknown Meme Template'));
}

Prevention

When it happens

Trigger: Requesting /macro/meme/ (or calling the meme engine) with a template name whose underlying template file/macro does not exist: template macro deleted after being referenced, name typo, or a fresh install missing default macro images.

Common situations: Custom meme templates removed or renamed; bookmarks/links embedding an old template name; macro images garbage collected or pruned.

Related errors


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