PluginNotFoundException thrown by VDB provider call, related to search_api_node_grants field

Created on 3 June 2025, 5 days ago

Problem/Motivation

This issue is encountered with Pinecone VDB provider but I think the issue belongs here. With a RAG agent configured to search an index backed by Pinecone, I get the following error:

Warning: Undefined array key 1 in Drupal\ai\Base\AiVdbProviderClientBase->isMultiple() (line 383 of /var/www/html/web/modules/contrib/ai/src/Base/AiVdbProviderClientBase.php)
#0 /var/www/html/web/core/includes/bootstrap.inc(108): _drupal_error_handler_real()
#1 /var/www/html/web/modules/contrib/ai/src/Base/AiVdbProviderClientBase.php(383): _drupal_error_handler()
#2 /var/www/html/web/modules/contrib/ai_vdb_provider_pinecone/src/Plugin/VdbProvider/PineconeProvider.php(497): Drupal\ai\Base\AiVdbProviderClientBase->isMultiple()
#3 /var/www/html/web/modules/contrib/ai_vdb_provider_pinecone/src/Plugin/VdbProvider/PineconeProvider.php(484): Drupal\ai_vdb_provider_pinecone\Plugin\VdbProvider\PineconeProvider->processConditionGroup()
#4 /var/www/html/web/modules/contrib/ai_vdb_provider_pinecone/src/Plugin/VdbProvider/PineconeProvider.php(464): Drupal\ai_vdb_provider_pinecone\Plugin\VdbProvider\PineconeProvider->processConditionGroup()
#5 /var/www/html/web/modules/contrib/ai/modules/ai_search/src/Plugin/search_api/backend/SearchApiAiSearchBackend.php(413): Drupal\ai_vdb_provider_pinecone\Plugin\VdbProvider\PineconeProvider->prepareFilters()
#6 /var/www/html/web/modules/contrib/search_api/src/Entity/Server.php(483): Drupal\ai_search\Plugin\search_api\backend\SearchApiAiSearchBackend->search()
#7 /var/www/html/web/modules/contrib/search_api/src/Query/Query.php(549): Drupal\search_api\Entity\Server->search()
#8 /var/www/html/web/modules/contrib/ai/modules/ai_search/src/Plugin/AiFunctionCall/RagTool.php(130): Drupal\search_api\Query\Query->execute()
#9 /var/www/html/web/modules/contrib/ai_agents/src/PluginBase/AiAgentEntityWrapper.php(886): Drupal\ai_search\Plugin\AiFunctionCall\RagTool->execute()
#10 /var/www/html/web/modules/contrib/ai_agents/src/PluginBase/AiAgentEntityWrapper.php(409): Drupal\ai_agents\PluginBase\AiAgentEntityWrapper->executeTool()
#11 /var/www/html/web/modules/contrib/ai_agents/src/PluginBase/AiAgentEntityWrapper.php(476): Drupal\ai_agents\PluginBase\AiAgentEntityWrapper->determineSolvability()
#12 /var/www/html/web/modules/contrib/ai_agents/src/Plugin/AiFunctionCall/AiAgentWrapper.php(175): Drupal\ai_agents\PluginBase\AiAgentEntityWrapper->determineSolvability()
#13 /var/www/html/web/modules/contrib/ai_agents/src/PluginBase/AiAgentEntityWrapper.php(886): Drupal\ai_agents\Plugin\AiFunctionCall\AiAgentWrapper->execute()
#14 /var/www/html/web/modules/contrib/ai_agents/src/PluginBase/AiAgentEntityWrapper.php(409): Drupal\ai_agents\PluginBase\AiAgentEntityWrapper->executeTool()
#15 /var/www/html/web/modules/contrib/ai_agents/src/PluginBase/AiAgentEntityWrapper.php(476): Drupal\ai_agents\PluginBase\AiAgentEntityWrapper->determineSolvability()
#16 /var/www/html/web/modules/contrib/ai/modules/ai_assistant_api/src/Service/AgentRunner.php(48): Drupal\ai_agents\PluginBase\AiAgentEntityWrapper->determineSolvability()
#17 /var/www/html/web/modules/contrib/ai/modules/ai_assistant_api/src/AiAssistantApiRunner.php(309): Drupal\ai_assistant_api\Service\AgentRunner->runAsAgent()
#18 /var/www/html/web/modules/contrib/ai/modules/ai_chatbot/src/Controller/DeepChatApi.php(160): Drupal\ai_assistant_api\AiAssistantApiRunner->process()
#19 [internal function]: Drupal\ai_chatbot\Controller\DeepChatApi->api()
#20 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array()
#21 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(593): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#22 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(121): Drupal\Core\Render\Renderer->executeInRenderContext()
#23 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext()
#24 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(183): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#25 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw()
#26 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/Session.php(53): Symfony\Component\HttpKernel\HttpKernel->handle()
#27 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
#28 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
#29 /var/www/html/web/core/modules/big_pipe/src/StackMiddleware/ContentLength.php(32): Drupal\Core\StackMiddleware\ContentLength->handle()
#30 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(116): Drupal\big_pipe\StackMiddleware\ContentLength->handle()
#31 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(90): Drupal\page_cache\StackMiddleware\PageCache->pass()
#32 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\page_cache\StackMiddleware\PageCache->handle()
#33 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
#34 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(36): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
#35 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\Core\StackMiddleware\AjaxPageState->handle()
#36 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(709): Drupal\Core\StackMiddleware\StackedHttpKernel->handle()
#37 /var/www/html/web/index.php(19): Drupal\Core\DrupalKernel->handle()

The problematic issue is in the function AiVdbProviderClientBase::isMultiple. The field being acted on is search_api_node_grants.

  public function isMultiple(FieldInterface $field): bool {
    [$fieldName] = explode(':', $field->getPropertyPath());
    [, $entity_type] = explode(':', $field->getDatasourceId());
    $fields = $this->entityFieldManager->getFieldStorageDefinitions($entity_type);
    foreach ($fields as $field) {
      if ($field->getName() === $fieldName) {
        $cardinality = $field->getCardinality();
        return !($cardinality === 1);
      }
    }
    return TRUE;
  }

Processing $field->getDatasourceId() results in $entity_type being set to null. It is probably more appropriate for parent methods to handle issues like this rather than being handled on a one-off basis by individual provider plugins.

Steps to reproduce

Install latest 1.1.x ai module.
Install ai_vdb_provider_pinecone 1.1.0-beta2.
Add an index backed by Pinecone with Content access and Entity status processors.
Add a agent that can use the RAG tool.
As a user who is not user 1 (it works fine for user 1 because user 1 I believe circumvents node grants entirely), chat with the agent and get it to use the RAG tool.
Verify you get the $entity_type is null and eventually get a PluginNotFoundException.

Proposed resolution

I'm not sure the correct course of action other than improve error handling in the isMultiple method or somewhere else.

Remaining tasks

User interface changes

API changes

Data model changes

πŸ› Bug report
Status

Active

Version

1.1

Component

Providers

Created by

πŸ‡ΊπŸ‡ΈUnited States lpeabody

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @lpeabody
  • πŸ‡ΊπŸ‡ΈUnited States lpeabody

    Adding what looks like a duplicate, or at least related issue. Leaving mine open for now since it has more details.

    Digging further, perhaps there is some issue with the way the ContentAccess processor plugin is creating the field item.

    Search API 8.x-1.38

    From Drupal\search_api\Plugin\search_api\processor\ContentAccess::preIndexSave:

      public function preIndexSave() {
        foreach ($this->index->getDatasources() as $datasource_id => $datasource) {
          $entity_type = $datasource->getEntityTypeId();
          if (in_array($entity_type, ['node', 'comment'])) {
            $this->ensureField($datasource_id, 'status', 'boolean');
            if ($entity_type == 'node') {
              $this->ensureField($datasource_id, 'uid', 'integer');
            }
          }
        }
    
        $field = $this->ensureField(NULL, 'search_api_node_grants', 'string');
        $field->setHidden();
      }
    
  • πŸ‡ΊπŸ‡ΈUnited States lpeabody

    I guess the question to ask is, is there a way for \Drupal\ai\Base\AiVdbProviderClientBase::isMultiple to handle the situation where Field::$datasourceId is null?

Production build 0.71.5 2024