{"record":{"id":"83b3a3047ffdc1f8","repo":"zylon-ai/private-gpt","slug":"semantic-search-tool-requires-an-ingested-artifact","errorCode":null,"errorMessage":"Semantic search tool requires an ingested artifact context.","messagePattern":"Semantic search tool requires an ingested artifact context\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/tools/processors/semantic_search_processor.py","lineNumber":41,"sourceCode":"        semantic_search_tool_builder: SemanticSearchToolBuilder,\n    ) -> None:\n        self._builder = semantic_search_tool_builder\n\n    async def intercept(self, request: ResolvedChatRequest) -> bool:\n        for tool in request.tool_config.tools:\n            if not _tool_matches(\n                tool, SEMANTIC_SEARCH_TOOL_NAME\n            ) or not _is_unresolved_tool(tool):\n                continue\n\n            tool_context = _get_tool_context(request, tool)\n            ingested_artifacts = (\n                [a for a in tool_context if isinstance(a, IngestedArtifact)]\n                if tool_context\n                else None\n            )\n            if not ingested_artifacts:\n                raise ValueError(\n                    \"Semantic search tool requires an ingested artifact context.\",\n                )\n            if len(ingested_artifacts) > 1:\n                raise ValueError(\"Only one ingested context is supported.\")\n\n            resolved = await self._builder.build_tool(\n                model_id=request.system.model,\n                name=tool.name or SEMANTIC_SEARCH_TOOL_NAME,\n                type=tool.type or SEMANTIC_SEARCH_TOOL_NAME + \"_v1\",\n                context_filter=ingested_artifacts[0].context_filter,\n                generate_citations=request.citation.enabled,\n                validate=request.tool_config.validation_mode,\n                token_limit=request.context.maximum_context_length,\n            )\n            return _replace_tool(request, tool, [resolved])\n        return False\n","sourceCodeStart":23,"sourceCodeEnd":58,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/tools/processors/semantic_search_processor.py#L23-L58","documentation":"Raised by the SemanticSearchProcessor interceptor when the semantic search tool is present in a request but its tool context has no IngestedArtifact. Semantic search needs an ingested corpus (with its context_filter) to build the retrieval tool, so the request is rejected before tool resolution.","triggerScenarios":"Enabling SEMANTIC_SEARCH_TOOL_NAME in tool_config.tools while tool_context is None/empty or contains only other artifact types (e.g. SqlDatabaseArtifact, SkillArtifact).","commonSituations":"Enabling 'search' tools by default in a UI without selecting a knowledge source; ingesting documents but forgetting to reference them as an IngestedArtifact in the tool context; multi-tool requests where the artifact was attached to the wrong tool.","solutions":["Attach exactly one IngestedArtifact (carrying the context_filter of the ingested corpus) to the semantic search tool's context","Or drop the semantic search tool from the request when no ingested corpus is in scope","Confirm ingestion completed and produced a context_filter before referencing it"],"exampleFix":"# before\ntools=[ToolConfig(name=SEMANTIC_SEARCH_TOOL_NAME)]\n# after\ntools=[\n    ToolConfig(\n        name=SEMANTIC_SEARCH_TOOL_NAME,\n        context=[IngestedArtifact(context_filter=ContextFilter(filters=...))],\n    )\n]","handlingStrategy":"validation","validationCode":"ingested = [a for a in (tool_context or []) if isinstance(a, IngestedArtifact)]\nif not ingested:\n    # do not include SEMANTIC_SEARCH_TOOL_NAME in the request, or attach an IngestedArtifact","typeGuard":"def is_ingested_artifact(ctx: object) -> bool:\n    return isinstance(ctx, IngestedArtifact)","tryCatchPattern":"try:\n    resp = await client.chat(request)\nexcept ValueError as e:\n    if \"requires an ingested artifact context\" in str(e):\n        # attach IngestedArtifact(context_filter=...) and resend\n        raise","preventionTips":["Gate semantic search behind selection of an ingested corpus in the UI/API layer","Keep a mapping tool_name -> required artifact type and validate requests against it","Confirm ingestion completed (context_filter exists) before exposing the search tool"],"tags":["tools","validation","semantic-search","rag"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}