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
- Default the variable at assignment or in the template: {% set tags = tags ?? [] %} before using 'in'
- Fix the operand to the actual container: {{ 'active' in user.roles }} (array), not a scalar field
- 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
- Default nullable variables before 'in' checks: {% set xs = xs ?? [] %}
- Assign normalized (array) data to views from controllers
- Use 'in' only against known array/string fields
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
- Macro '{name}' does not exist
- The extension is not valid
- 'always' must be a bool value
- 'prefix' must be a string
- 'separator' must be a string
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/ab4eafc3aea264a6.
Report an issue: GitHub.