doctrine/orm · error · QueryException

The hint "HINT_CACHE_EVICT" is not valid for select statemen

Error message

The hint "HINT_CACHE_EVICT" is not valid for select statements.

What it means

Query::HINT_CACHE_EVICT instructs the ORM to evict the second-level-cache entity region affected by a DQL statement. It only makes sense for UPDATE/DELETE: during execute(), evictEntityCacheRegion() inspects the AST and throws a QueryException if the statement is a SelectStatement, because a SELECT has no affected entity region to evict.

Source

Thrown at src/Query.php:334

        assert($cache !== null);

        $statements = (array) $executor->getSqlStatements(); // Type casted since it can either be a string or an array

        foreach ($statements as $statement) {
            $cacheKeys = $this->queryCacheProfile->generateCacheKeys($statement, $sqlParams, $types, $connectionParams);
            $cache->deleteItem(reset($cacheKeys));
        }
    }

    /**
     * Evict entity cache region
     */
    private function evictEntityCacheRegion(): void
    {
        $AST = $this->getAST();

        if ($AST instanceof SelectStatement) {
            throw new QueryException('The hint "HINT_CACHE_EVICT" is not valid for select statements.');
        }

        $className = $AST instanceof DeleteStatement
            ? $AST->deleteClause->abstractSchemaName
            : $AST->updateClause->abstractSchemaName;

        $this->em->getCache()->evictEntityRegion($className);
    }

    /**
     * Processes query parameter mappings.
     *
     * @param array<list<int>> $paramMappings
     *
     * @return mixed[][]
     * @phpstan-return array{0: list<mixed>, 1: array}
     *
     * @throws Query\QueryException

View on GitHub (pinned to d9b9ff7301)

Solutions

  1. Remove the HINT_CACHE_EVICT hint from SELECT queries — set it only on UPDATE/DELETE DQL
  2. To invalidate cached query/entity data after a select-driven change, evict explicitly: $em->getCache()->evictEntityRegion(Entity::class) or ->evictEntity(Entity::class, $id)
  3. Keep hint-setting conditional on the statement type when hints are configured centrally

Example fix

// before
$q = $em->createQuery('SELECT u FROM App\Entity\User u WHERE u.id = :id');
$q->setHint(Query::HINT_CACHE_EVICT, true); // throws on execute

// after
$q = $em->createQuery('SELECT u FROM App\Entity\User u WHERE u.id = :id');
// evict manually if needed:
$em->getCache()->evictEntity(User::class, $id);
Defensive patterns

Strategy: validation

Validate before calling

// Only set the hint on UPDATE/DELETE DQL
if (in_array($queryType, ['update', 'delete'], true)) {
    $query->setHint(Query::HINT_CACHE_EVICT, true);
}

Try / catch

try { $result = $query->execute(); } catch (QueryException $e) { if (str_contains($e->getMessage(), 'HINT_CACHE_EVICT')) { $query->setHint(Query::HINT_CACHE_EVICT, false); $result = $query->execute(); } else { throw $e; } }

Prevention

When it happens

Trigger: $query->setHint(Query::HINT_CACHE_EVICT, true) followed by executing a SELECT DQL query while second-level cache is enabled (hasCache) — the check runs in _doExecute() before parameter processing.

Common situations: Copy-pasting a cache-eviction hint between queries; applying the hint to a query builder that later becomes a select; blindly enabling all cache hints when turning on the second-level cache.

Related errors


AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21). Data as JSON: /api/errors/82970b30183e52b3. Report an issue: GitHub.