phalcon/cphalcon · error · Phalcon\Mvc\View\Engine\Volt\Exceptions\InvalidHaystack

Invalid haystack

Error message

Invalid haystack

What it means

Volt::inFilter() backs the template 'in' operator / 'in' filter: needle-in-haystack succeeds for array haystacks (in_array) and string haystacks (mb_strpos/strpos substring check); any other haystack type — null, int, float, bool, object — throws InvalidHaystack (phalcon/Mvc/View/Engine/Volt.zep:169). The operator deliberately supports only containers where membership is well-defined.

Source

Thrown at phalcon/Mvc/View/Engine/Volt.zep:169

    public function isIncluded(var needle, var haystack) -> bool
    {
        if unlikely null === needle {
            let needle = "";
        }

        if typeof haystack == "array" {
            return in_array(needle, haystack);
        }

        if typeof haystack == "string" {
            if this->phpFunctionExists("mb_strpos") {
                return mb_strpos(haystack, needle) !== false;
            }

            return strpos(haystack, needle) !== false;
        }

        throw new InvalidHaystack();
    }

    /**
     * Length filter. If an array/object is passed a count is performed otherwise a strlen/mb_strlen
     *
     * @param mixed item
     *
     * @return int
     */
    public function length(var item) -> int
    {
        if unlikely null === item {
            let item = "";
        }

        if typeof item == "object" || typeof item == "array" {
            return count(item);
        }

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Default the variable at assignment or in the template: {% set tags = tags ?? [] %} before using 'in'
  2. Fix the operand to the actual container: {{ 'active' in user.roles }} (array), not a scalar field
  3. Cast/normalize data in the controller before assigning to the view (e.g. (array) $dto->tags)

Example fix

// before (volt)
{% if 'urgent' in ticket.flags %} ... {% endif %} {# flags can be null #}

// after
{% set flags = ticket.flags ?? [] %}
{% if 'urgent' in flags %} ... {% endif %}
Defensive patterns

Strategy: type-guard

Validate before calling

$haystack = $haystack ?? [];
if (!is_array($haystack) && !is_string($haystack)) {
    throw new \InvalidArgumentException('Volt in-filter haystack must be array or string');
}

Type guard

function acceptsHaystack(mixed $haystack): bool
{
    return is_array($haystack) || is_string($haystack);
}

Prevention

When it happens

Trigger: Template {{ 'active' in user.status }} where user.status is null/int; {{ 5 in count(items) }} mixing up a count with the collection; a controller assigns null for a missing variable used with 'in'; {{ key in objectProperty }} where the property is a stdClass.

Common situations: Optional model relations/fields that arrive null; API responses decoded into objects rather than arrays used with 'in'; Volt templates written against arrays that later changed to iterable objects or scalars.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/ab4eafc3aea264a6. Report an issue: GitHub.