phalcon/cphalcon · error · Phalcon\Tag\Exception
Value at index: '{key}' type: '{type}' cannot be rendered
Error message
Value at index: '{key}' type: '{type}' cannot be rendered What it means
When Phalcon\Tag renders an attribute list, every string key with a non-null value becomes a key="value" pair. PHP arrays and resources have no meaningful string form, so an attribute value of either type throws Phalcon\Tag\Exception ("Value at index: '{key}' type: '{type}' cannot be rendered"), with {type} from gettype(). Only these two types are rejected — scalars pass (objects survive if they stringify during concatenation).
Source
Thrown at phalcon/Tag.zep:1004
}
}
for key, value in attributes {
if !isset attrs[key] {
let attrs[key] = value;
}
}
let escaper = <EscaperInterface> self::getEscaper(attributes);
unset attrs["escape"];
let attrParts = [];
for key, value in attrs {
if typeof key == "string" && value !== null {
if unlikely (typeof value == "array" || typeof value == "resource") {
throw new Exception(
"Value at index: '" . key . "' type: '" . gettype(value) . "' cannot be rendered"
);
}
if escaper {
let escaped = escaper->attributes(value);
} else {
let escaped = value;
}
let attrParts[] = key . "=\"" . escaped . "\"";
}
}
if empty attrParts {
return code;
}
View on GitHub (pinned to b7419de9cd)
Solutions
- Flatten list attributes yourself: 'class' => implode(' ', $classes)
- Filter out resource values before rendering
- Map domain data to an explicit scalar-only attribute whitelist instead of passing raw arrays
Example fix
// before
echo \Phalcon\Tag::textField(['name' => 'email', 'class' => ['form-control', 'w-100']]);
// after
echo \Phalcon\Tag::textField([
'name' => 'email',
'class' => implode(' ', ['form-control', 'w-100']),
]); Defensive patterns
Strategy: validation
Validate before calling
$attributes = array_filter($attributes, function ($value) {
return !is_resource($value);
});
$attributes = array_map(function ($value) {
return is_array($value) ? implode(' ', $value) : $value;
}, $attributes);
echo \Phalcon\Tag::textField($attributes); Type guard
function isRenderableAttributeValue($value): bool
{
return null === $value || (!is_array($value) && !is_resource($value));
} Prevention
- Implode list-like attributes (class, rel, data-*) yourself before passing them
- Map domain data to an explicit scalar-only attribute whitelist at the boundary
- Never pass file handles, Resultsets, or decoded nested arrays directly as tag params
When it happens
Trigger: Tag::textField(['name' => 'email', 'class' => ['form-control', 'w-100']]) — array attribute; a file/stream handle ending up in an attribute array; merging structured domain data into params so extra keys become attributes.
Common situations: Building 'class' or 'data-*' attributes as arrays out of convenience; passing whole config/request arrays as tag params expecting unknown keys to be ignored.
Related errors
- RouterFactory::load requires an array or Phalcon\Config\Conf
- Invalid haystack
- The extension is not valid
- 'always' must be a bool value
- 'prefix' must be a string
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/5d216bb6d90f7201.
Report an issue: GitHub.