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

  1. Flatten arrays to a string before setting: ->set('class', implode(' ', ['btn', 'btn-primary']))
  2. Serialize structured values explicitly: ->set('data-config', json_encode($config))
  3. 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

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


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