phalcon/cphalcon · error · Phalcon\Html\Exceptions\AttributeNotRenderable
Value at index: "{key}" type: "{type}" cannot be rendered
Error message
Value at index: "{key}" type: "{type}" cannot be rendered What it means
Phalcon\Html\Attributes::render() serializes every attribute as key="value" through an HTML escaper that only accepts scalars. When a value is an array or a resource, no unambiguous string representation exists, so it throws AttributeNotRenderable with the key and its gettype().
Source
Thrown at phalcon/Html/Attributes.zep:85
/**
* Just in case remove the "escape" attribute
*/
unset results["escape"];
/**
* Escape values through the configurable AttributeEscaper so a single
* implementation owns attribute escaping. ENT_QUOTES reproduces the
* previous hardcoded htmlspecialchars() call byte for byte - the
* "utf-8" encoding and double-encode defaults already match.
*/
let escaper = new AttributeEscaper();
escaper->setFlags(ENT_QUOTES);
let result = "";
for key, value in results {
if typeof key === "string" && null !== value {
if (typeof value === "array" || is_resource(value)) {
throw new AttributeNotRenderable(key, gettype(value));
}
let result .= key . "=\""
. escaper->escape(value)
. "\" ";
}
}
return result;
}
}
View on GitHub (pinned to b7419de9cd)
Solutions
- Flatten arrays to a string before setting: ->set('class', implode(' ', ['btn', 'btn-primary']))
- Serialize structured values explicitly: ->set('data-config', json_encode($config))
- Filter the attributes so only scalar (string|int|float|bool) values remain before render()
Example fix
// before
$attributes->set('class', ['btn', 'btn-primary']);
echo $attributes->render(); // AttributeNotRenderable
// after
$attributes->set('class', implode(' ', ['btn', 'btn-primary']));
echo $attributes->render(); Defensive patterns
Strategy: type-guard
Validate before calling
$renderable = [];
foreach ($attributes as $key => $value) {
if (is_array($value)) {
$value = implode(' ', $value);
}
if (is_scalar($value) || $value === null) {
$renderable[$key] = $value;
}
}
$attrs = new \Phalcon\Html\Attributes($renderable); Type guard
/** @param mixed $value */
function isRenderableAttributeValue($value): bool
{
return $value === null || is_scalar($value);
} Try / catch
try {
echo $attributes->render();
} catch (\Phalcon\Html\Exceptions\AttributeNotRenderable $e) {
// message names the offending key and its type; drop or serialize it, then retry
error_log($e->getMessage());
} Prevention
- Flatten array values (implode) or json_encode() them at the point where attributes are set
- Never merge unvalidated request arrays directly into Attributes
- Filter attributes through an is_scalar() pass in shared render helpers
When it happens
Trigger: echo $attributes after $attributes->set('class', ['btn', 'btn-primary']); passing a stream/resource (for example an uploaded-file handle) as an attribute value; merging nested arrays from user input into an Attributes instance.
Common situations: Setting data-* attributes from decoded JSON that contains nested objects; building element attributes from unvalidated request arrays; assigning a file handle as a pseudo-attribute.
Related errors
- {message}
- The 'using' parameter requires exactly two values
- Resultset returned an invalid value
- Service {name} is not registered
- No route matched the request.
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/14fbe133a12ab7f6.
Report an issue: GitHub.