{"record":{"id":"8100d343d06694a1","repo":"doctrine/orm","slug":"hydraterowdata-not-implemented-by-this-hydrator","errorCode":null,"errorMessage":"hydrateRowData() not implemented by this hydrator.","messagePattern":"hydrateRowData\\(\\) not implemented by this hydrator\\.","errorType":"exception","errorClass":"Doctrine\\ORM\\Internal\\Hydration\\HydrationException","httpStatus":null,"severity":"error","filePath":"src/Internal/Hydration/AbstractHydrator.php","lineNumber":235,"sourceCode":"    }\n\n    protected function cleanupAfterRowIteration(): void\n    {\n    }\n\n    /**\n     * Hydrates a single row from the current statement instance.\n     *\n     * Template method.\n     *\n     * @param mixed[] $row    The row data.\n     * @param mixed[] $result The result to fill.\n     *\n     * @throws HydrationException\n     */\n    protected function hydrateRowData(array $row, array &$result): void\n    {\n        throw new HydrationException('hydrateRowData() not implemented by this hydrator.');\n    }\n\n    /**\n     * Hydrates all rows from the current statement instance at once.\n     */\n    abstract protected function hydrateAllData(): mixed;\n\n    /**\n     * Processes a row of the result set.\n     *\n     * Used for identity-based hydration (HYDRATE_OBJECT and HYDRATE_ARRAY).\n     * Puts the elements of a result row into a new array, grouped by the dql alias\n     * they belong to. The column names in the result set are mapped to their\n     * field names during this procedure as well as any necessary conversions on\n     * the values applied. Scalar values are kept in a specific key 'scalars'.\n     *\n     * @param mixed[] $data SQL Result Row.\n     * @phpstan-param array<string, string> $id                 Dql-Alias => ID-Hash.","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/doctrine/orm/blob/d9b9ff73016bf598ae07515f97289ce8074e97a5/src/Internal/Hydration/AbstractHydrator.php#L217-L253","documentation":"HydrationException from AbstractHydrator::hydrateRowData() (src/Internal/Hydration/AbstractHydrator.php:235). This is the default, unimplemented template method. Row-by-row hydration (used by AbstractQuery::toIterable()) needs hydrateRowData(); hydrators that only implement hydrateAllData() — such as SingleScalarHydrator and ScalarColumnHydrator — cannot stream rows and hit this stub.","triggerScenarios":"Calling $query->toIterable($params, $hydrationMode) with Query::HYDRATE_SINGLE_SCALAR or Query::HYDRATE_SCALAR_COLUMN (or a custom hydrator registered without hydrateRowData()). ObjectHydrator, ArrayHydrator, ScalarHydrator and SimpleObjectHydrator implement the method; the scalar one-shot modes do not.","commonSituations":"Rewriting batch jobs from getResult()/getSingleScalarResult() to toIterable() for memory reasons and keeping the old hydration mode; custom hydrators written only for hydrateAll(); passing a hydration-mode constant as the second toIterable() argument without checking which modes stream.","solutions":["Switch the iteration to a supported mode: toIterable($params, Query::HYDRATE_ARRAY), HYDRATE_OBJECT or HYDRATE_SCALAR.","For single-column streams, iterate HYDRATE_SCALAR and take the first value of each row, or loop over the plain getSingleColumnResult() array if the data set fits memory.","For a custom hydrator used with toIterable(), implement protected function hydrateRowData(array $row, array &$result): void.","If you truly need one scalar per row streamed, use a DBAL statement ($conn->prepare(...)->executeQuery()->iterateColumn()) instead of the ORM hydrator."],"exampleFix":"// before\n$query = $em->createQuery('SELECT COUNT(o) FROM App\\Entity\\Order o GROUP BY o.customer');\nforeach ($query->toIterable([], Query::HYDRATE_SINGLE_SCALAR) as $count) { ... }\n    // HydrationException: hydrateRowData() not implemented by this hydrator.\n\n// after\nforeach ($query->toIterable([], Query::HYDRATE_SCALAR) as $row) {\n    $count = (int) reset($row); // first (only) column of the row\n}","handlingStrategy":"validation","validationCode":"$streamable = [\n    \\Doctrine\\ORM\\Query::HYDRATE_OBJECT,\n    \\Doctrine\\ORM\\Query::HYDRATE_ARRAY,\n    \\Doctrine\\ORM\\Query::HYDRATE_SCALAR,\n];\nif (! in_array($mode, $streamable, true)) {\n    throw new InvalidArgumentException(\"Hydration mode {$mode} cannot be used with toIterable()\");\n}\nforeach ($query->toIterable($params, $mode) as $row) { /* ... */ }","typeGuard":"/** @param int|string $mode AbstractQuery::HYDRATE_* */\nfunction isIterableHydrationMode(int|string $mode): bool\n{\n    return in_array($mode, [\n        \\Doctrine\\ORM\\Query::HYDRATE_OBJECT,\n        \\Doctrine\\ORM\\Query::HYDRATE_ARRAY,\n        \\Doctrine\\ORM\\Query::HYDRATE_SCALAR,\n    ], true);\n}","tryCatchPattern":null,"preventionTips":["Bookmark that toIterable() supports OBJECT, ARRAY and SCALAR modes only.","For custom hydrators used with toIterable(), implement hydrateRowData() (and hydrateAllData()).","Use DBAL iterateColumn()/iterateAssociative() for streaming scalar data."],"tags":["doctrine-orm","hydration","to-iterate","batch-processing"],"backgroundTag":"unsupported-hydration-mode","analyzedSha":"d9b9ff73016bf598ae07515f97289ce8074e97a5","analyzedAt":"2026-08-21T06:13:15.863Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}