octobercms/october · error · ApplicationException

The markup filter/function for '{$this->name}' is not callab

Error message

The markup filter/function for '{$this->name}' is not callable.

What it means

MarkupExtensionItem wraps a Twig filter or function registered through a plugin's registerMarkupTags() (or CMS markup extensions). getTwigCallback() is called when the item is bound into Twig; for non-wildcard names it checks the stored callback with is_callable() and throws ApplicationException naming the filter/function when the callback cannot actually be invoked. Wildcard registrations (e.g. 'str_*' routing to Str::*) bypass this check and resolve dynamically.

Source

Thrown at modules/system/classes/MarkupExtensionItem.php:170

    /**
     * getTwigCallback returns a callback function suitable for Twig
     */
    public function getTwigCallback()
    {
        // Handle a wildcard function
        if (strpos($this->name, '*') !== false && $this->isWildCallable()) {
            return function ($name) {
                $arguments = array_slice(func_get_args(), 1);
                $method = $this->getWildCallback(Str::camel($name));
                return $method(...$arguments);
            };
        }

        // Cannot call item method
        $callable = $this->callback;
        if (!is_callable($callable)) {
            throw new ApplicationException("The markup filter/function for '{$this->name}' is not callable.");
        }

        // Wrap in a closure to prevent Twig from reflecting facades
        // when applying its named closure support
        return function(...$args) use ($callable) {
            return $callable(...$args);
        };
    }

    /**
     * getTwigOptions returns options passed to the Twig definition
     */
    public function getTwigOptions(): array
    {
        return ($this->escapeOutput ? [] : ['is_safe' => ['html']]) + $this->options;
    }

    /**

View on GitHub (pinned to b608633a7e)

Solutions

  1. Fix the callable: use [MyHelper::class, 'method'], a namespaced function string like 'strtoupper', or a closure.
  2. Verify the method exists, is public (and static if called statically), and the class is autoloaded with the correct namespace.
  3. Replace 'Class@method' strings with the array form — PHP's is_callable() rejects them.
  4. Sanity-check with is_callable($callback) right after registering before reloading the frontend.

Example fix

// before
public function registerMarkupTags()
{
    return ['filters' => ['excerpt' => 'Acme\Blog\Classes\Excerpt@make']];
}

// after
public function registerMarkupTags()
{
    return ['filters' => ['excerpt' => [\Acme\Blog\Classes\Excerpt::class, 'make']]];
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate registerMarkupTags() output before returning it
public function registerMarkupTags()
{
    $tags = ['filters' => ['excerpt' => [Excerpt::class, 'make']]];

    foreach ($tags['filters'] ?? [] as $name => $callback) {
        if (!is_callable($callback)) {
            throw new RuntimeException("Markup filter '{$name}' callback is not callable.");
        }
    }

    return $tags;
}

Type guard

function isMarkupCallbackValid($callback): bool
{
    if (is_string($callback) && strpos($callback, '@') !== false) {
        return false; // 'Class@method' form is never callable in PHP
    }
    return is_callable($callback);
}

Prevention

When it happens

Trigger: registerMarkupTags() returning ['filters' => ['excerpt' => 'acme_excerpt']] where that function does not exist; ['functions' => ['tweet' => ['Acme\Blog\Classes\Twitter', 'send']]] where send is not a public static method or the class name has a typo; callbacks written in 'Class@method' string form, which PHP does not treat as callable; referencing a class that is not autoloadable at registration time.

Common situations: First render of a page/template after adding a new markup tag; renaming a helper class without updating registerMarkupTags(); plugin authors copying the 'Class@method' convention from Laravel-ish contexts where October requires [Class::class, 'method'] or a closure; definitions supplied via YAML/JSON where the callable string was mangled.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/8dae9126b88f1bef. Report an issue: GitHub.