phalcon/cphalcon · error · Phalcon\Html\Exceptions\InvalidResultsetValue

Resultset returned an invalid value

Error message

Resultset returned an invalid value

What it means

While iterating the resultset, ResultsetData::resolve() requires every row to be an object or an array so the two using columns can be read from it. A row that is a scalar, null, or resource — for example a resultset of single-column values — throws InvalidResultsetValue because no field can be read.

Source

Thrown at phalcon/Html/Helper/Input/Select/ResultsetData.zep:130

    /**
     * Walks the resultset once, building both the option map and the
     * per-option resolved attribute map. Closures in `attributesMap`
     * receive the current row; static values are passed through.
     * `false` or `null` values skip the attribute entirely.
     */
    protected function resolve() -> void
    {
        var attrName, attrSpec, attrValue, attrs, option, optionAttrs,
            optionText, optionValue, options, usingZero, usingOne;

        let usingZero   = this->using[0],
            usingOne    = this->using[1],
            options     = [],
            attrs       = [];

        for option in this->resultset {
            if typeof option != "object" && typeof option != "array" {
                throw new InvalidResultsetValue();
            }

            let optionValue = this->readField(option, usingZero),
                optionText  = this->readField(option, usingOne);

            let options[optionValue] = optionText;

            if !empty(this->attributesMap) {
                let optionAttrs = [];

                for attrName, attrSpec in this->attributesMap {
                    if is_callable(attrSpec) {
                        let attrValue = call_user_func(attrSpec, option);
                    } else {
                        let attrValue = attrSpec;
                    }

                    if false !== attrValue && null !== attrValue {

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Select the full row (at least both using columns) so rows hydrate as objects or arrays
  2. Map scalar rows before passing: $rows = array_map(fn($v) => ['value' => $v, 'text' => $v], $scalars)
  3. For scalar value/text pairs, skip the resultset helper and pass a plain options array

Example fix

// before — single-column fetch, rows are strings
$rows = $connection->query('SELECT name FROM categories', [], [\PDO::FETCH_COLUMN]);

// after — full rows hydrate as arrays
$rows = $connection->query('SELECT id, name FROM categories')->fetchAll();
Defensive patterns

Strategy: validation

Validate before calling

foreach ($resultset as $index => $row) {
    if (!is_object($row) && !is_array($row)) {
        throw new \InvalidArgumentException(
            "Resultset row {$index} is a " . gettype($row) . '; rows must be objects or arrays'
        );
    }
}

$data = new \Phalcon\Html\Helper\Input\Select\ResultsetData($resultset, $using, $attributesMap);

Type guard

/** @param mixed $row */
function isSelectableRow($row): bool
{
    return is_object($row) || is_array($row);
}

Try / catch

try {
    $data = new ResultsetData($resultset, $using, $attributesMap);
} catch (\Phalcon\Html\Exceptions\InvalidResultsetValue $e) {
    // rows are scalars; rebuild as [value => text] options instead
    $options = [];
    foreach ($resultset as $row) {
        $options[(string) $row] = (string) $row;
    }
    $select->setOptions($options);
}

Prevention

When it happens

Trigger: The query selects a single column with a fetch mode returning scalars (PDO::FETCH_COLUMN), so every row is a string; an aggregate row that hydrates to null; a custom resultset implementation yielding scalar items.

Common situations: Optimizing a SELECT to one column for speed and then feeding it to the select helper; changing the DB fetch mode globally; resultsets hydrated as scalars in reporting queries.

Related errors


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